Perl 객체지향


Perl에는 두 가지 다른 객체 지향 프로그래밍 구현이 있습니다.

  • 하나는 익명 해시 테이블을 기반으로 합니다. 각 객체 인스턴스의 본질은 포인터 참조입니다. 익명의 해시 테이블에. 이 익명 해시 테이블에는 모든 인스턴스 속성이 저장됩니다.

  • 두 번째는 클래스를 정의할 때 각 인스턴스 속성에 대한 배열을 생성하며, 각 객체 인스턴스의 본질은 이러한 배열에 대한 포인터입니다. 행 인덱스로. 이러한 배열에는 모든 인스턴스 속성이 저장됩니다.


객체 지향의 기본 개념

객체 지향에는 많은 기본 개념이 있는데 여기서는 객체, 클래스, 메서드 세 가지를 받아들입니다.

  • 객체 : 객체는 클래스의 데이터 항목에 대한 참조입니다. .

  • 클래스: 클래스는 객체 메서드를 제공하는 클래스가 포함된 Perl 패키지입니다.

  • 메서드: 메서드는 Perl 서브루틴이고 클래스 이름은 첫 번째 매개변수입니다.

Perl은 bless() 함수를 제공합니다. bless는 객체를 생성하는 데 사용됩니다. Bless는 참조를 클래스 이름과 연결하고 참조를 반환하여 객체를 생성합니다.


클래스 정의

클래스는 단순한 패키지입니다.

패키지를 클래스로 사용할 수 있고, 패키지에 포함된 함수를 클래스의 메소드로 사용할 수 있습니다.

Perl 패키지는 독립적인 네임스페이스를 제공하므로 다른 패키지의 메서드와 변수 이름이 충돌하지 않습니다.

Perl 클래스의 파일 확장자는 .pm입니다.

다음으로 Person 클래스를 만듭니다.

package Person;

클래스의 코드 범위는 스크립트 파일의 마지막 줄이나 다음 패키지 키워드 앞에 도달합니다.


객체 생성 및 사용

클래스의 인스턴스(객체)를 생성하려면 생성자를 정의해야 하며, 대부분의 프로그램은 클래스 이름을 생성자로 사용합니다. 어떤 이름이든 가능합니다. Perl에서 사용됩니다.

다양한 Perl 변수를 Perl 객체로 사용할 수 있습니다. 대부분의 경우 참조 배열이나 해시를 사용합니다.

다음으로 Perl의 해시 참조를 사용하여 Person 클래스의 생성자를 만듭니다.

객체를 생성할 때 객체에 대한 참조를 반환하는 서브루틴인 생성자를 제공해야 합니다.

예제는 다음과 같습니다.

package Person;
sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # 输出用户信息
    print "名字:$self->{_firstName}\n";
    print "姓氏:$self->{_lastName}\n";
    print "编号:$self->{_ssn}\n";
    bless $self, $class;
    return $self;
}

다음으로 개체를 만듭니다.

$object = new Person( "小明", "王", 23234345);

메서드 정의

Perl 클래스의 메서드 이것은 단지 Perl 하위 프로그램일 뿐이며 멤버 함수라고도 알려진 프로그램일 뿐입니다.

객체 지향 Perl에서 Perl의 메서드 정의는 특별한 구문을 제공하지 않지만 메서드의 첫 번째 매개 변수가 참조되는 개체 또는 패키지라고 규정합니다.

Perl은 private 변수를 제공하지 않지만 보조 메소드를 통해 객체 데이터를 관리할 수 있습니다.

다음으로 이름을 가져오는 메서드를 정의합니다:

sub getFirstName {
    return $self->{_firstName};
}

다음과 같이 작성할 수도 있습니다:

sub setFirstName {
    my ( $self, $firstName ) = @_;
    $self->{_firstName} = $firstName if defined($firstName);
    return $self->{_firstName};
}

다음으로 Person.pm 파일의 코드를 다음과 같이 수정합니다. 다음과 같습니다:

#!/usr/bin/perl 

package Person;

sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # 输出用户信息
    print "名字:$self->{_firstName}\n";
    print "姓氏:$self->{_lastName}\n";
    print "编号:$self->{_ssn}\n";
    bless $self, $class;
    return $self;
}
sub setFirstName {
    my ( $self, $firstName ) = @_;
    $self->{_firstName} = $firstName if defined($firstName);
    return $self->{_firstName};
}

sub getFirstName {
    my( $self ) = @_;
    return $self->{_firstName};
}
1;

employee.pl 스크립트 코드는 다음과 같습니다.

#!/usr/bin/perl

use Person;

$object = new Person( "小明", "王", 23234345);
# 获取姓名
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

위 프로그램을 실행한 후 출력 결과는 다음과 같습니다.

$ perl employee.pl
名字:小明
姓氏:王
编号:23234345
设置前姓名为 : 小明
设置后姓名为 : 小强

상속

Perl에서 클래스 메서드는 @ISA 배열을 통해 상속됩니다. 이 배열에는 다른 패키지(클래스)의 이름이 포함됩니다. 변수 상속은 명시적으로 설정되어야 합니다.

다중 상속은 @ISA 배열에 여러 클래스(패키지) 이름이 포함되어 있음을 의미합니다.

@ISA를 통해 메소드만 상속할 수 있으며, 데이터는 상속할 수 없습니다.

다음으로 Person 클래스를 상속하는 Employee 클래스를 만듭니다.

Employee.pm 파일의 코드는 다음과 같습니다.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # 从 Person 继承

이제 Employee 클래스에는 Person 클래스의 모든 메소드와 속성이 포함되어 있습니다. main.pl에 다음 코드를 입력합니다. 파일을 만들고 실행합니다:

#!/usr/bin/perl

use Employee;

$object = new Employee( "小明", "王", 23234345);
# 获取姓名
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

위 프로그램을 실행한 후 출력 결과는 다음과 같습니다.

$ perl main.pl
名字:小明
姓氏:王
编号:23234345
设置前姓名为 : 小明
设置后姓名为 : 小强

Method rewriting

위의 예에서 Employee 클래스는 Person 클래스이지만 Person 클래스인 경우 메서드가 요구 사항을 충족할 수 없으면 메서드를 다시 작성해야 합니다.

다음으로 Employee 클래스에 몇 가지 새로운 메서드를 추가하고 Person 클래스의 메서드를 재정의합니다.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # 从 Person 继承

# 重写构造函数
sub new {
    my ($class) = @_;

    # 调用父类的构造函数
    my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
    # 添加更多属性
    $self->{_id}   = undef;
    $self->{_title} = undef;
    bless $self, $class;
    return $self;
}

# 重写方法
sub getFirstName {
    my( $self ) = @_;
    # 这是子类函数
    print "这是子类函数\n";
    return $self->{_firstName};
}

# 添加方法
sub setLastName{
    my ( $self, $lastName ) = @_;
    $self->{_lastName} = $lastName if defined($lastName);
    return $self->{_lastName};
}

sub getLastName {
    my( $self ) = @_;
    return $self->{_lastName};
}

1;

main.pl 파일에 다음 코드를 입력하고 실행합니다.

#!/usr/bin/perl

use Employee;

$object = new Employee( "小明", "王", 23234345);
# 获取姓名,使用修改后的构造函数
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

위 프로그램을 실행한 후 출력 결과는 다음과 같습니다.

$ perl main.pl
名字:小明
姓氏:王
编号:23234345
这是子类函数
设置前姓名为 : 小明
这是子类函数
设置后姓名为 : 小强

기본적으로 로드됨

현재 클래스에 있는 경우 현재 클래스의 모든 기본 클래스 및 UNIVERSAL 클래스를 요청할 방법을 찾을 수 없습니다. 이때 AUTOLOAD()라는 메소드를 다시 찾는다. AUTOLOAD가 발견되면 전역 변수 $AUTOLOAD를 호출하고 누락된 메서드의 정규화된 이름으로 설정합니다.

작동하지 않으면 Perl은 오류와 함께 실패합니다.

기본 클래스의 AUTOLOAD를 상속하지 않으려면 매우 간단합니다. 단 한 문장이면 됩니다:

sub AUTOLOAD;

소멸자와 가비지 수집

개체의 마지막 참조를 해제하면 개체가 자동으로 삭제됩니다.

파괴 중에 작업을 수행하려면 클래스에 "DESTROY"라는 메서드를 정의할 수 있습니다. 적절한 시간에 자동으로 호출되어 원하는 대로 추가 정리 작업을 수행합니다.

package MyClass;
...
sub DESTROY
{
    print "MyClass::DESTROY called\n";
}

Perl은 객체 참조를 다음과 같이 처리합니다. 전달된 유일한 인수는 DESTROY입니다. 이 참조는 읽기 전용이므로 $_[0]에 액세스하여 수정할 수 없습니다. (번역자 주: perlsub 참조) 그러나 객체 자체(예: "${$_[0]" 또는 "@{$_[0]}" 및 "%{$_[0]}" 등)은 여전히 ​​쓰기 가능합니다.

소멸자가 반환되기 전에 개체 참조를 다시 축복하면 Perl은 소멸자가 반환된 후 다시 축복한 개체의 DESTROY 메서드를 호출합니다. 이를 통해 기본 클래스 또는 지정한 다른 클래스의 소멸자를 호출할 수 있습니다. DESTROY는 수동으로 호출할 수도 있지만 일반적으로 그렇게 할 필요는 없습니다.

현재 개체가 해제되면 현재 개체에 포함된 다른 개체도 자동으로 해제됩니다.


Perl 객체지향 예제

다음 예제를 통해 Perl의 객체지향 응용을 더 잘 이해할 수 있습니다.

#!/usr/bin/perl

# 下面是简单的类实现
package MyClass;

sub new
{
   print "MyClass::new called\n";
   my $type = shift;            # 包名
   my $self = {};               # 引用空哈希
   return bless $self, $type;   
}

sub DESTROY
{
   print "MyClass::DESTROY called\n";
}

sub MyMethod
{
   print "MyClass::MyMethod called!\n";
}


# 继承实现
package MySubClass;

@ISA = qw( MyClass );

sub new
{
   print "MySubClass::new called\n";
   my $type = shift;            # 包名
   my $self = MyClass->new;     # 引用空哈希
   return bless $self, $type;  
}

sub DESTROY
{
   print "MySubClass::DESTROY called\n";
}

sub MyMethod
{
   my $self = shift;
   $self->SUPER::MyMethod();
   print "   MySubClass::MyMethod called!\n";
}

# 调用以上类的主程序
package main;

print "调用 MyClass 方法\n";

$myObject = MyClass->new();
$myObject->MyMethod();

print "调用 MySubClass 方法\n";

$myObject2 = MySubClass->new();
$myObject2->MyMethod();

print "创建一个作用域对象\n";
{
  my $myObject2 = MyClass->new();
}
# 自动调用析构函数

print "创建对象\n";
$myObject3 = MyClass->new();
undef $myObject3;

print "脚本执行结束...\n";
# 自动执行析构函数

위 프로그램을 실행하면 출력 결과는 다음과 같습니다:

调用 MyClass 方法
MyClass::new called
MyClass::MyMethod called!
调用 MySubClass 方法
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
   MySubClass::MyMethod called!
创建一个作用域对象
MyClass::new called
MyClass::DESTROY called
创建对象
MyClass::new called
MyClass::DESTROY called
脚本执行结束...
MyClass::DESTROY called
MySubClass::DESTROY called