Perl OOP
Summary: in this tutorial, you will learn about Perl Object-Oriented Programming or Perl OOP. You will learn how to create a simple Perl class and use it in other programs.
Besides procedural programming, Perl also provides you with object-orient programming paradigm.
Object-Oriented Programming Concepts
If you are not familiar with object-oriented programming, the following are the fundamental concepts to help you get started.
Object
An object is a single entity that combines both data and code. Object is described in the following terms:
- Actions or methods describe what it can do. It is the code part of the object.
- Attributes or properties describe what information the object conveys. It is the data part of the object.
An object can be anything tangible or intangible. A phone is a tangible object that has attributes: serial , name , price , etc. You can change one of this information through methods that the phone object provides e.g., set_name , get_name , etc.
Class
A class is a blueprint or template of similar objects. A house is an object but the house blueprint is a class. From the house blueprint you can build as many houses as you want. We often say an object is an instance of a class e.g., a phone is an instance of Product class.
We typically use UML to model class including its attributes and methods. The following is the Product class in UML diagram.
Encapsulation
Through object, you can hide its complexity which is known as abstraction or encapsulation in object oriented programming. It means the client of the object does not need to care about the internal logic of the object but still can use the object through its interfaces (methods).
Inheritance
Inheritance means one class inherits both attributes and methods from another class. Inheritance enables you to reuse and extend existing classes without copy-n-paste the code or re-invent the wheel.
- A class that other classes inherit from is called base class or superclass.
- A class that inherits from other class called subclass or derived class.
Polymorphism
Polymorphism means “many forms” in Greek. It means a method call can behave differently depending on the type of the object that calls it.
Perl OOP rules
There are three important rules in Perl object oriented programming:
Defining the first Perl class
We are going to define the Product class in Perl. With rule #1: a class is a package so here is the definition of the Product class in Product.pm file:
Code language: Perl (perl)package Product; use strict; use warnings; sub new < >1;
In Perl, we use a subroutine or method named new() to construct the object. The subroutine name is not mandatory so you can use any subroutine name you want, but be consistent.
Let’s add some attributes to the Product class.
Code language: PHP (php)# init product with serial, name and price sub new < my ($class,$args) = @_; my $self = bless < serial =>$args->, name => $args->, price => $args-> >, $class; >
Whenever you call the new() method, Perl automatically passes the class name Product as the first argument to the special array @_.
When you create an object, you actually create a reference that knows what class it belongs to. The built-in function bless is used to bless the reference to the class and return an instance of the class.
The following illustrates the syntax of the bless() function:
object = bless reference, classname;
We’ve passed a hash reference to the bless() function. You can pass any kind of reference to the bless function e.g., array reference, however, it is much easier to work with a hash reference.
We are ready to use the Product class in other programs.
Let’s create a new program that uses the Product class.
Code language: Perl (perl)#!/usr/bin/perl use strict; use warnings; use Product; my $iphone = Product->new(< serial =>"100", name => "iPhone 5", price => 650.00>);
We called the method new() of the Product class and get an object $iphone . We passed a hash reference to the new() method containing serial , name and price .
Let’s add some methods which are known as getters/setters to manipulate attributes of the Product class.
The following illustrates the complete Product class.
Code language: Perl (perl)package Product; use strict; use warnings; # init product with serial, name and price sub new< my ($class,$args) = @_; my $self = bless < serial => $args->, name => $args->, price => $args-> >, $class; > # get name of the product sub get_name< my $self = shift; return $self->; > # set new name for the product sub set_name< my ($self,$new_name) = @_; $self-> = $new_name; > # get price of the product sub get_price< my $self = shift; return $self->; > # set price for the product sub set_price< my ($self,$new_price) = @_; $self-> = $new_price; > # get serial sub get_serial< my $self = shift; return $self->; > # set serial sub set_serial< my ($self,$new_price) = @_; $self-> = $new_price; > # return formatted string of the product sub to_string< my $self = shift; return "Serial: $self->\nName: $self->\nPrice: $self->USD\n"; > 1;
The following program illustrates how to use the Product class:
Code language: Perl (perl)#!/usr/bin/perl use strict; use warnings; use Product; my $iphone = Product->new(< serial =>"100", name => "iPhone", price => 650.00>); my $nexus = Product->new(< serial =>"101", name => "Nexus", price => 299.00>); print $iphone->to_string(); print $nexus->to_string();
The output of the program is as follows:
In this tutorial, we’ve shown you how to use Perl object-oriented feature. It is quite simple. We hope with this short tutorial, you can get the idea and explore Perl OOP further.
Moose: ООП в Perl
Moose — расширения для Perl 5, позволяющее упростить реализацию ООП.
Создание класса происходит очень легко:
package MyClass; use Moose;
все, пустой класс создан. Он может иметь произвольное количество: аттрибутов, методов, суперклассов, модификаторов метода, конструктор(1шт), деструктор(1шт) и мета-класс(1шт) который содержит все метаинформацию о данном классе.
Теперь подробнее об этих составляющих:
Класс
Каждый класс является подклассом Moose::Object. По умолчанию создает кучу всяких полезных объектов, в виде мета-классов и других присущих суперклассу объектов, к которым можно получить доступ после создания.
Подкласс
package User; use Moose; extends 'Person'; has 'username' => ( is => 'rw' );
множественное наследование, указываем классы через запятую: extends ‘Foo’, ‘Bar’;
Аттрибуты
Обязательно должно быть имя у аттрибута, может иметь различное количество свойств: флаг read/write, type, accessor method, delegations, значение по умолчанию и др.
По умолчанию Moose хранит аттрибуты в экземпляре класса, как хэш. Доступ к ним можно получить через аксессоры.
has — объявляем аттрибут
опция is может иметь значения [ro|rw|bare] read-only либо read-write или bare — без аксессоров к данному аттрибуту.
Геттеры и сеттеры можно установить так:
has 'weight' => ( is => 'rw', reader => 'get_weight', writer => 'set_weight', );
predicate — если аттрибут «undef» или другое ложное значение, то возвратит истину.
clearer — сбрасывает аттрибут
clearer — сбрасывает аттрибут
has 'ssn' => ( is => 'rw', clearer => 'clear_ssn', predicate => 'has_ssn', );
$person->has_ssn; # false $person->ssn(undef); $person->ssn; # returns undef $person->has_ssn; # true $person->clear_ssn; $person->ssn; # returns undef $person->has_ssn; # false $person->ssn('123-45-6789'); $person->ssn; # returns '123-45-6789' $person->has_ssn; # true
Необходимость в установки аттрибута
можно установить с помощью свойства: required => 1
по умолчанию все аттрибуты необязательны.
Аттрибуты можно установить по умолчанию двумя способами.
has 'size' => ( is => 'ro', default => 'medium', predicate => 'has_size', );
my $person = Person->new(); $person->size; # medium $person->has_size; # true
А можно установить ссылку на метод:
has 'size' => ( is => 'ro', default => sub < ( 'small', 'medium', 'large' )[ int( rand 3 ) ] >, predicate => 'has_size', );
has 'size' => ( is => 'ro', builder => '_build_size', predicate => 'has_size', ); sub _build_size
builder рекомендуют использовать вместо default.
Откладываем установку аттрибута в последнюю очередь
этого можно достичь установив свойство: lazy => 1
особенно необходимо, когда начальное значение аттрибута зависит от других факторов.
Еще один плюс в использовании этого свойства, в том что аттрибут будет вычисляться только в том случае, если потребуется, а если же он вообще не потребуется, то мы сохраним CPU time.
Типы аттрибутов
могут быть такой же тип как и любая перл структура: isa => ‘Str’
а могут быть и объектом: does => ‘MyApp::Object’
Установка нескольких аттрибутов
has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' );
for my $name ( qw( x y ) ) < my $builder = '_build_' . $name; has $name =>( is => 'ro', isa => 'Int', builder => $builder ); >
Методы
Всякая функция, объявленная в классе — это метод класса.
Модификаторы методов
Роль
поведение или состояние, которое должен реализовать данный класс. Аналог интерфейса в других ООязыках.
Создается с помощью use Moose::Role;
package Eq; use Moose::Role; requires 'equal_to'; sub not_equal_to < my ( $self, $other ) = @_; not $self->equal_to($other); >
хотя роль выглядит как класс, но это не класс, нельзя создать экземпляр роли. Слово requires говорит нам, что любой класс, использующий данную роль должен реализовать метод ‘equal_to’.
package Comparable; use Moose; with 'Eq'; sub equal_to < my ( $self, $other ) = @_; $self->compare($other) == 0; > sub compare < my ( $self, $other ) = @_; $self->amount $other->amount; >
Конструктор/Деструктор
Их никогда не нужно явно переопределять, но если все же возникнета такая необходимость то можно использовать BUILD() и DEMOLISH() для конструктора и деструктора соотвественно.
Metaclass
Метакласс описывает класс. С Moose каждый класс дает «meta()», который возвращает Moose::Meta::Class объект. Он говорит о том что представляет из себя данный класс.
my $meta = User->meta(); for my $attribute ( $meta->get_all_attributes ) < print $attribute->name(), "\n"; if ( $attribute->has_type_constraint ) < print " type: ", $attribute->type_constraint->name, "\n"; > > for my $method ( $meta->get_all_methods ) < print $method->name, "\n"; >
Очистка мусора
происходит если установить в начале класса: use namespace::autoclean;
или в конце класса: no Moose;
Ускорение работы классов
__PACKAGE__->meta->make_immutable;
Вот и все, этих знаний должно быть достаточно, чтобы успешно создавать ООП структуры на языке Perl, но для более глубокого пониманию, конечно же лучше углубиться в документацию и… да да в исходный код модулей (ну это уж для особых случаев, хотя в данном случае, любопытство никому не помешает).