Perl Language
객체 지향 Perl
수색…
객체 생성하기
다른 많은 언어와 달리 Perl에는 객체에 메모리를 할당하는 생성자가 없습니다. 대신 데이터 구조를 만들고 데이터로 채우는 클래스 메소드를 작성해야합니다 (팩토리 메소드 디자인 패턴으로 알 수 있음).
package Point;
use strict;
sub new {
my ($class, $x, $y) = @_;
my $self = { x => $x, y => $y }; # store object data in a hash
bless $self, $class; # bind the hash to the class
return $self;
}
이 방법은 다음과 같이 사용할 수 있습니다.
my $point = Point->new(1, 2.5);
화살표 연산자 ->
가 메소드와 함께 사용될 때마다 왼쪽 피연산자가 주어진 인수 목록 앞에 추가됩니다. 따라서, new
값의 @_
에는 값 ('Point', 1, 2.5)
됩니다.
new
이름에는 특별한 것이 없습니다. 원하는 경우 팩토리 메서드를 호출 할 수 있습니다.
해시에는 특별한 것이 없습니다. 다음과 같은 방법으로 동일한 작업을 수행 할 수 있습니다.
package Point;
use strict;
sub new {
my ($class, @coord) = @_;
my $self = \@coord;
bless $self, $class;
return $self;
}
일반적으로 모든 참조는 스칼라 참조조차도 객체가 될 수 있습니다. 그러나 대부분의 경우 해시는 객체 데이터를 표현하는 가장 편리한 방법입니다.
클래스 정의하기
일반적으로 Perl 클래스는 패키지입니다. 일반 패키지와 같이 데이터와 메소드를 포함 할 수 있습니다.
package Point;
use strict;
my $CANVAS_SIZE = [1000, 1000];
sub new {
...
}
sub polar_coordinates {
...
}
1;
패키지에서 선언 된 변수는 객체 (인스턴스) 변수가 아니라 클래스 변수라는 점에 유의해야합니다. 패키지 수준 변수를 변경하면 클래스의 모든 객체에 영향을줍니다. 개체 별 데이터를 저장하는 방법은 "개체 만들기"를 참조하십시오.
클래스 패키지를 구체적으로 만드는 것은 화살표 연산자 ->
입니다. 맨손으로 사용한 후 사용할 수 있습니다.
Point->new(...);
또는 스칼라 변수 (일반적으로 참조를 보유) 뒤에 :
my @polar = $point->polar_coordinates;
화살표의 왼쪽은 메소드의 주어진 인수 목록 앞에 추가됩니다. 예를 들어, 통화 후
Point->new(1, 2);
new
배열의 @_
에는 ('Point', 1, 2)
3 개의 인수가 포함됩니다.
클래스를 나타내는 패키지는이 규칙을 고려해야하며 모든 메서드에 추가 인수가 하나 있어야합니다.
상속 및 메서드 확인
클래스를 다른 클래스의 하위 클래스로 만들려면 parent
pragma를 사용합니다.
package Point;
use strict;
...
1;
package Point2D;
use strict;
use parent qw(Point);
...
1;
package Point3D;
use strict;
use parent qw(Point);
...
1;
Perl은 다중 상속을 허용합니다 :
package Point2D;
use strict;
use parent qw(Point PlanarObject);
...
1;
상속은 특정 상황에서 메서드가 호출되는 해결 방법입니다. 순수 Perl은 객체 데이터를 저장하는 데 사용되는 데이터 구조에 대한 규칙을 규정하지 않으므로 상속은 그와 아무 상관이 없습니다.
다음 클래스 계층을 고려하십시오.
package GeometryObject;
use strict;
sub transpose { ...}
1;
package Point;
use strict;
use parent qw(GeometryObject);
sub new { ... };
1;
package PlanarObject;
use strict;
use parent qw(GeometryObject);
sub transpose { ... }
1;
package Point2D;
use strict;
use parent qw(Point PlanarObject);
sub new { ... }
sub polar_coordinates { ... }
1;
메서드 확인은 다음과 같이 작동합니다.
시작점은 화살표 연산자의 왼쪽 피연산자로 정의됩니다.
맨손이면 :
Point2D->new(...);
... 또는 문자열을 담고있는 스칼라 변수 :
my $class = 'Point2D'; $class->new(...);
... 시작 지점은 해당 이름을 가진 패키지입니다 (두 예제 모두에서
Point2D
).왼쪽 피연산자가 축약 된 참조를 보유하는 스칼라 변수 인 경우 :
my $point = {...}; bless $point, 'Point2D'; # typically, it is encapsulated into class methods my @coord = $point->polar_coordinates;
시작점은 참조의 클래스입니다 (다시,
Point2D
). 화살표 연산자는 unblessed 참조에 대한 메소드를 호출하는 데 사용할 수 없습니다.
시작점에 필요한 메소드가 들어 있으면 간단히 호출됩니다.
따라서,
Point2D::new
가 존재하기 때문에,Point2D->new(...);
간단하게 그것을 부를 것이다.
시작점에 필수 메소드가 포함되어 있지 않으면
parent
클래스에서 깊이 우선 검색이 수행됩니다. 위의 예에서 검색 순서는 다음과 같습니다.-
Point2D
-
Point
(Point2D
최초의 부모) -
GeometryObject
(Point
부모) -
PlanarObject
(Point2D
두 번째 부모)
예를 들어, 다음 코드에서 :
my $point = Point2D->new(...); $point->transpose(...);
호출되는 방법은
GeometryObject::transpose
가에서 재정의 될지라도,PlanarObject::transpose
.-
시작점을 명시 적으로 설정할 수 있습니다.
앞의 예제에서, 다음과 같이
PlanarObject::transpose
명시 적으로 호출 할 수 있습니다.my $point = Point2D->new(...); $point->PlanarObject::transpose(...);
비슷한 방식으로
SUPER::
는 현재 클래스의 부모 클래스에서 메소드 검색을 수행합니다.예를 들어,
package Point2D; use strict; use parent qw(Point PlanarObject); sub new { (my $class, $x, $y) = @_; my $self = $class->SUPER::new; ... } 1;
Point2D::new
실행 중에Point::new
를 호출합니다.
클래스 및 객체 메소드
Perl에서 클래스 (정적)와 객체 (인스턴스) 메소드의 차이는 다른 언어 에서처럼 강력하지 않지만 여전히 존재합니다.
화살표 연산자의 왼쪽 피연산자 ->
는 호출 할 메소드의 첫 번째 인수가됩니다. 문자열 일 수 있습니다.
# the first argument of new is string 'Point' in both cases
Point->new(...);
my $class = 'Point';
$class->new(...);
또는 객체 참조 :
# reference contained in $point is the first argument of polar_coordinates
my $point = Point->new(...);
my @coord = $point->polar_coordinates;
클래스 메소드는 첫 번째 인수가 문자열이 될 것으로 예상하는 메소드이고 객체 메소드는 첫 번째 인수가 객체 참조가 될 것으로 기대하는 메소드입니다.
클래스 메서드는 일반적으로 클래스의 이름 인 첫 번째 인수로는 아무 것도 수행하지 않습니다. 일반적으로 Perl 자체에서만 메서드 확인에 사용됩니다. 따라서 일반적인 클래스 메서드를 개체에 대해서도 호출 할 수 있습니다.
my $width = Point->canvas_width;
my $point = Point->new(...);
my $width = $point->canvas_width;
이 구문은 허용되지만 종종 혼동을 줄 수 있으므로이를 피하는 것이 좋습니다.
객체 메소드는 객체 참조를 첫 번째 인수로받습니다. 따라서 클래스 메소드와 달리 객체 데이터를 처리 할 수 있습니다.
package Point;
use strict;
sub polar_coordinates {
my ($point) = @_;
my $x = $point->{x};
my $y = $point->{y};
return (sqrt($x * $x + $y * $y), atan2($y, $x));
}
1;
같은 방법으로 두 경우를 추적 할 수 있습니다 : 클래스 또는 객체 메소드로 호출되는 경우 :
sub universal_method {
my $self = shift;
if (ref $self) {
# object logic
...
}
else {
# class logic
...
}
}
현대 Perl에서 클래스 정의하기
사용 가능하지만, 처음부터 클래스 를 정의하는 것은 현대 Perl에서는 권장되지 않습니다. 더 많은 기능과 편리함을 제공하는 도우미 OO 시스템 중 하나를 사용하십시오. 이러한 시스템에는 다음이 있습니다.
Moose
- 펄 6 OO 디자인에 영감을 얻은Class::Accessor
- 무스에 대한 간단한 대안Class::Tiny
- 정말로 최소한의 클래스 빌더
엘크
package Foo;
use Moose;
has bar => (is => 'ro'); # a read-only property
has baz => (is => 'rw', isa => 'Bool'); # a read-write boolean property
sub qux {
my $self = shift;
my $barIsBaz = $self->bar eq 'baz'; # property getter
$self->baz($barIsBaz); # property setter
}
클래스 :: 접근 자 (무스 문법)
package Foo;
use Class::Accessor 'antlers';
has bar => (is => 'ro'); # a read-only property
has baz => (is => 'rw', isa => 'Bool'); # a read-write property (only 'is' supported, the type is ignored)
클래스 :: 접근 자 (기본 구문)
package Foo;
use base qw(Class::Accessor);
Foo->mk_accessors(qw(bar baz)); # some read-write properties
Foo->mk_accessors(qw(qux)); # a read-only property
클래스 :: Tiny
package Foo;
use Class::Tiny qw(bar baz); # just props
역할
Perl에서의 역할은 근본적으로
- 메소드와 속성 세트.
- 수업에 직접 주입.
역할은 모든 클래스 (역할을 소비 한다고 말함 )에 구성 되거나 적용될 수있는 기능을 제공합니다. 역할은 상속 될 수 없지만 다른 역할에 의해 소비 될 수 있습니다.
역할은 소비 클래스가 메서드 자체를 구현하는 대신 (Java 또는 C #의 인터페이스와 마찬가지로) 일부 메서드를 구현 해야 할 수도 있습니다.
Perl에는 역할에 대한 지원 기능이 기본적으로 없지만 이러한 지원을 제공하는 CPAN 클래스가 있습니다.
package Chatty;
use Moose::Role;
requires 'introduce'; # a method consuming classes must implement
sub greet { # a method already implemented in the role
print "Hi!\n";
}
package Parrot;
use Moose;
with 'Chatty';
sub introduce {
print "I'm Buddy.\n";
}
OO 시스템이 역할 (예 : Class::Accessor
또는 Class::Tiny
)에 대한 지원을 제공하지 않는 경우에 사용하십시오. 속성을 지원하지 않습니다.
package Chatty;
use Role::Tiny;
requires 'introduce'; # a method consuming classes must implement
sub greet { # a method already implemented in the role
print "Hi!\n";
}
package Parrot;
use Class::Tiny;
use Role::Tiny::With;
with 'Chatty';
sub introduce {
print "I'm Buddy.\n";
}