Учебники

Объектно-ориентированное программирование в PERL

Мы уже изучали ссылки на анонимные массивы и хэши Perl и Perl. Объектно-ориентированная концепция в Perl во многом основана на ссылках, анонимных массивах и хешах. Давайте начнем изучать основные понятия объектно-ориентированного Perl.

Основы объекта

Есть три основных термина, объясненных с точки зрения того, как Perl обрабатывает объекты. Термины объект, класс и метод.

  • Объект в Perl — это просто ссылка на тип данных, который знает, к какому классу он принадлежит. Объект хранится в виде ссылки в скалярной переменной. Поскольку скаляр содержит только ссылку на объект, один и тот же скаляр может содержать разные объекты в разных классах.

  • Класс в Perl — это пакет, который содержит соответствующие методы, необходимые для создания объектов и управления ими.

  • Метод в Perl — это подпрограмма, определенная пакетом. Первым аргументом метода является ссылка на объект или имя пакета, в зависимости от того, влияет ли метод на текущий объект или класс.

Объект в Perl — это просто ссылка на тип данных, который знает, к какому классу он принадлежит. Объект хранится в виде ссылки в скалярной переменной. Поскольку скаляр содержит только ссылку на объект, один и тот же скаляр может содержать разные объекты в разных классах.

Класс в Perl — это пакет, который содержит соответствующие методы, необходимые для создания объектов и управления ими.

Метод в Perl — это подпрограмма, определенная пакетом. Первым аргументом метода является ссылка на объект или имя пакета, в зависимости от того, влияет ли метод на текущий объект или класс.

Perl предоставляет функцию bless () , которая используется для возврата ссылки, которая в конечном итоге становится объектом.

Определение класса

Определить класс в Perl очень просто. Класс соответствует Пакету Perl в его самой простой форме. Чтобы создать класс в Perl, мы сначала собираем пакет.

Пакет — это автономная единица пользовательских переменных и подпрограмм, которые можно использовать снова и снова.

Пакеты Perl предоставляют отдельное пространство имен в программе Perl, в котором подпрограммы и переменные не зависят от конфликтующих с другими пакетами.

Чтобы объявить класс с именем Person в Perl, мы делаем —

package Person;

Область определения пакета распространяется до конца файла или до тех пор, пока не встретится другое ключевое слово пакета.

Создание и использование объектов

Для создания экземпляра класса (объекта) нам нужен конструктор объекта. Этот конструктор является методом, определенным в пакете. Большинство программистов предпочитают называть этот метод конструктора объекта новым, но в Perl вы можете использовать любое имя.

Вы можете использовать любой тип переменной Perl в качестве объекта в Perl. Большинство программистов на Perl выбирают либо ссылки на массивы, либо хэши.

Давайте создадим наш конструктор для нашего класса Person, используя ссылку на хеш Perl. При создании объекта вам необходимо предоставить конструктор, который является подпрограммой в пакете, который возвращает ссылку на объект. Ссылка на объект создается путем благословения ссылки на класс пакета. Например —

package Person;
sub new {
   my $class = shift;
   my $self = {
      _firstName => shift,
      _lastName  => shift,
      _ssn       => shift,
   };
   # Print all the values just for clarification.
   print "First Name is $self->{_firstName}\n";
   print "Last Name is $self->{_lastName}\n";
   print "SSN is $self->{_ssn}\n";
   bless $self, $class;
   return $self;
}

Теперь давайте посмотрим, как создать объект.

$object = new Person( "Mohammad", "Saleem", 23234345);

Вы можете использовать простой хеш в вашем констуркторе, если вы не хотите присваивать какое-либо значение какой-либо переменной класса. Например —

package Person;
sub new {
   my $class = shift;
   my $self = {};
   bless $self, $class;
   return $self;
}

Определение методов

Другие объектно-ориентированные языки имеют концепцию безопасности данных для предотвращения непосредственного изменения программистом данных объекта и предоставляют методы доступа для изменения данных объекта. Perl не имеет закрытых переменных, но мы все еще можем использовать концепцию вспомогательных методов для манипулирования данными объекта.

Давайте определим вспомогательный метод, чтобы получить имя человека —

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

Еще одна вспомогательная функция для установки имени человека —

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

Теперь давайте рассмотрим полный пример: сохраните пакет Person и вспомогательные функции в файле Person.pm.

#!/usr/bin/perl 

package Person;

sub new {
   my $class = shift;
   my $self = {
      _firstName => shift,
      _lastName  => shift,
      _ssn       => shift,
   };
   # Print all the values just for clarification.
   print "First Name is $self->{_firstName}\n";
   print "Last Name is $self->{_lastName}\n";
   print "SSN is $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;

Теперь давайте используем объект Person в файле employee.pl следующим образом:

#!/usr/bin/perl

use Person;

$object = new Person( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";

Когда мы выполняем вышеуказанную программу, она выдает следующий результат —

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.

наследование

У объектно-ориентированного программирования есть очень хорошая и полезная концепция, называемая наследованием. Наследование просто означает, что свойства и методы родительского класса будут доступны дочерним классам. Таким образом, вам не нужно писать один и тот же код снова и снова, вы можете просто наследовать родительский класс.

Например, у нас может быть класс Employee, который наследуется от Person. Это называется отношениями isa, потому что работник — это человек. В Perl есть специальная переменная @ISA, чтобы помочь с этим. @ISA регулирует (метод) наследования.

Ниже приведены важные моменты, которые следует учитывать при использовании наследования:

  • Perl ищет в классе указанного объекта данный метод или атрибут, т. Е. Переменную.

  • Perl ищет классы, определенные в массиве @ISA класса объекта.

  • Если в шагах 1 или 2 метод не найден, Perl использует подпрограмму AUTOLOAD, если она найдена в дереве @ISA.

  • Если соответствующий метод все еще не может быть найден, то Perl ищет метод в классе (пакете) UNIVERSAL, который входит в состав стандартной библиотеки Perl.

  • Если метод все еще не найден, Perl сдается и вызывает исключение времени выполнения.

Perl ищет в классе указанного объекта данный метод или атрибут, т. Е. Переменную.

Perl ищет классы, определенные в массиве @ISA класса объекта.

Если в шагах 1 или 2 метод не найден, Perl использует подпрограмму AUTOLOAD, если она найдена в дереве @ISA.

Если соответствующий метод все еще не может быть найден, то Perl ищет метод в классе (пакете) UNIVERSAL, который входит в состав стандартной библиотеки Perl.

Если метод все еще не найден, Perl сдается и вызывает исключение времени выполнения.

Поэтому, чтобы создать новый класс Employee, который будет наследовать методы и атрибуты от нашего класса Person, мы просто кодируем следующим образом: Сохраните этот код в Employee.pm.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # inherits from Person

Теперь класс Employee имеет все методы и атрибуты, унаследованные от класса Person, и вы можете использовать их следующим образом: Используйте файл main.pl для его проверки —

#!/usr/bin/perl

use Employee;

$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";

Когда мы выполняем вышеуказанную программу, она выдает следующий результат —

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.

Переопределение метода

Дочерний класс Employee наследует все методы родительского класса Person. Но если вы хотите переопределить эти методы в своем дочернем классе, вы можете сделать это, предоставив собственную реализацию. Вы можете добавить свои дополнительные функции в дочерний класс или добавить или изменить функциональность существующих методов в его родительском классе. Это можно сделать следующим образом: изменить файл Employee.pm.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # inherits from Person

# Override constructor
sub new {
   my ($class) = @_;

   # Call the constructor of the parent class, Person.
   my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
   # Add few more attributes
   $self->{_id}   = undef;
   $self->{_title} = undef;
   bless $self, $class;
   return $self;
}

# Override helper function
sub getFirstName {
   my( $self ) = @_;
   # This is child class function.
   print "This is child class helper function\n";
   return $self->{_firstName};
}

# Add more methods
sub setLastName{
   my ( $self, $lastName ) = @_;
   $self->{_lastName} = $lastName if defined($lastName);
   return $self->{_lastName};
}

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

1;

Теперь давайте снова попробуем использовать объект Employee в нашем файле main.pl и выполнить его.

#!/usr/bin/perl

use Employee;

$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";

Когда мы выполняем вышеуказанную программу, она выдает следующий результат —

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
This is child class helper function
Before Setting First Name is : Mohammad
This is child class helper function
After Setting First Name is : Mohd.

Автозагрузка по умолчанию

Perl предлагает функцию, которую вы не найдете ни в одном другом языке программирования: подпрограмма по умолчанию. Это означает, что если вы определяете функцию с именем AUTOLOAD (), то любые вызовы неопределенных подпрограмм будут автоматически вызывать функцию AUTOLOAD (). Имя отсутствующей подпрограммы доступно в этой подпрограмме как $ AUTOLOAD.

Функция автозагрузки по умолчанию очень полезна для обработки ошибок. Вот пример реализации AUTOLOAD, вы можете реализовать эту функцию по-своему.

sub AUTOLOAD {
   my $self = shift;
   my $type = ref ($self) || croak "$self is not an object";
   my $field = $AUTOLOAD;
   $field =~ s/.*://;
   unless (exists $self->{$field}) {
      croak "$field does not exist in object/class $type";
   }
   if (@_) {
      return $self->($name) = shift;
   } else {
      return $self->($name);
   }
}

Деструкторы и сборщик мусора

Если вы программировали с использованием объектно-ориентированного программирования ранее, то вы будете знать о необходимости создания деструктора, чтобы освободить память, выделенную для объекта, когда вы закончили его использовать. Perl делает это автоматически для вас, как только объект выходит из области видимости.

Если вы хотите реализовать свой деструктор, который должен позаботиться о закрытии файлов или о дополнительной обработке, вам нужно определить специальный метод, называемый DESTROY . Этот метод будет вызван для объекта непосредственно перед тем, как Perl освободит выделенную ему память. В остальном метод DESTROY такой же, как и любой другой метод, и вы можете реализовать любую логику внутри этого метода.

Метод деструктора — это просто функция-член (подпрограмма) с именем DESTROY, которая будет вызываться автоматически в следующих случаях:

  • Когда переменная ссылки на объект выходит из области видимости.
  • Когда переменная ссылки на объект не определена.
  • Когда скрипт заканчивается
  • Когда Perl-интерпретатор завершает работу

Например, вы можете просто поместить следующий метод DESTROY в ваш класс —

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

Пример объектно-ориентированного Perl

Вот еще один хороший пример, который поможет вам понять объектно-ориентированные концепции Perl. Поместите этот исходный код в любой файл perl и выполните его.

Live Demo

#!/usr/bin/perl

# Following is the implementation of simple Class.
package MyClass;

sub new {
   print "MyClass::new called\n";
   my $type = shift;            # The package/type name
   my $self = {};               # Reference to empty hash
   return bless $self, $type;   
}

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

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


# Following is the implemnetation of Inheritance.
package MySubClass;

@ISA = qw( MyClass );

sub new {
   print "MySubClass::new called\n";
   my $type = shift;            # The package/type name
   my $self = MyClass->new;     # Reference to empty hash
   return bless $self, $type;  
}

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

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

# Here is the main program using above classes.
package main;

print "Invoke MyClass method\n";

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

print "Invoke MySubClass method\n";

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

print "Create a scoped object\n";
{
   my $myObject2 = MyClass->new();
}
# Destructor is called automatically here

print "Create and undef an object\n";
$myObject3 = MyClass->new();
undef $myObject3;

print "Fall off the end of the script...\n";
# Remaining destructors are called automatically here

Когда мы выполняем вышеуказанную программу, она выдает следующий результат —