Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП Perl.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
21.43 Кб
Скачать

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

7 апреля 2011

Когда создавался Perl, ООП еще не был моден. Сейчас он моден, в связи с чем некоторые граждане, не обнаружив в этом языке любимых классов, испытывают культурный шок, плюются и идут учить модные PHP и Python. Тем не менее, если вы используете в своей работе Perl и хотите программировать в ООП стиле, язык не будет стоять у вас на пути. Единственная проблема, с которой вам предстоит столкнутся — это проблема выбора, потому что в Perl, как обычно, «there’s more than one way to do it».

Примечание: Для тех, кто не знает Perl, но хотел бы его освоить, в этом блоге есть соответствующая серия уроков.

1. Традиционные модули (еще не ооп)

Чуть более 99% скриптов на Perl — это небольшие утилиты в пару сотен строк кода. Но что делать в тех редких случаях, когда требуется написать большуюпрограмму, разбив ее код на несколько файлов? Традиционное решение, не имеющее отношения к ООП, выглядит следующим образом. Все функции выносятся в отдельные модули (файлы с расширением .pm). Основной же скрипт (файл .pl) подгружает эти модули, а те в свою очередь подгружают модули, от которых зависят сами. Скрипт берет функции, объявленные в подгруженных модулях, и с их помощью делает свое темное дело.

Рассмотрим пример модуля (файл MyLib.pm):

#!/usr/bin/perl

package MyLib;

use strict;

sub Test {

print "MyLib - Test Ok!\n";

}

1; # сообщает интерпретатору, что все ОК

… а также пример скрипта, использующего этот модуль:

#!/usr/bin/perl

use strict;

use MyLib;

MyLib::Test();

Теперь представим себе, что есть модуль, функции которого нам приходится использовать довольно часто. В этом случае некоторые функции было бы удобно импортировать в пространство имен скрипта. Перепишем пример соответствующим образом.

Файл MyLib.pm:

#!/usr/bin/perl

package MyLib;

use strict;

use Exporter 'import';

our @EXPORT_OK = qw/Test/;

sub Test {

print "MyLib - Test Ok!\n";

}

1;

Файл test.pl:

#!/usr/bin/perl

use strict;

use MyLib qw/Test/;

Test(); # вызовет MyLib::Test()

Подробности о модуле Exporter можно найти в CPAN’е.

2. Добавляем объектно-ориентированность

В Perl 5 есть три типа данных — скаляры, массивы и хэши. Как же получить с их помощью объекты? Оказывается, все очень просто. Берем специальную функцию bless(), передаем ей первым аргументом указатель на переменную (как правило, используются хэши) и название класса вторым аргументом. То, что было передано первым аргументом, становится объектом! Вот как это выглядит на практике.

Файл MyCalss.pm:

#!/usr/bin/perl

package MyClass; {

# ^ фигурные скобки - для красоты

# а в Perl >= 5.14 можно без точки с запятой

use strict;

sub new {

# получаем имя класса

my($class) = @_;

# создаем хэш, содержащий свойства объекта

my $self = {

name => 'MyClass',

version => '1.0',

};

# хэш превращается, превращается хэш...

bless $self, $class;

# ... в элегантный объект!

# эта строчка - просто для ясности кода

# bless и так возвращает свой первый аргумент

return $self;

}

# метод get_name();

sub get_name {

my($self) = @_; # ссылка на объект

return $self->{name}; # достаем имя из хэша

}

}

1; # ok!

Пример скрипта, использующего MyClass:

#!/usr/bin/perl

use strict;

use MyClass;

# создаем новый объект

# в конструктор можно было передать дополнительные аргументы

# которые шли бы в sub new() следом за именем класса

# my $cl = new MyClass(); # олдскульный стиль

my $cl = MyClass->new();

# доступ к имени можно получить напрямую

print "Name: ".$cl->{name}."\n";

# но правильнее делать это через гетер

# аналогично вызову MyClass::get_name($cl, другие-аргументы);

print "get_name() returns: ".$cl->get_name()."\n";

А вот — пример класса-наследника:

#!/usr/bin/perl

package MyClassChild; {

use base MyClass; # родительский класс

use strict;

# переопределяем конструктор

sub new {

my($class) = @_;

my $self = MyClass::new($class);

$self->{name} = "MyClassChild";

return $self;

}

# тут можно объявить дополнительные методы

}

1;

Тут все здорово и замечательно, но, к сожалению, нет инкапсуляции. Вернее, если я не ошибаюсь, это называется «инкапсуляция по соглашению». Это когда мы даем protected методам имена, начинающиеся, например, с одного подчеркивания, а private методам — имена, начинающиеся с двух подчеркиваний и говорим, что первые должны вызываться только из класса и его потомков, а вторые — только из класса. При желании можно даже написать небольшой скрипт, делающий проверку, что инкапсуляция нигде не нарушается. Я где-то слышал, что такой тип инкапсуляции вполне успешно используется в некоторых языках (SmallTalk ?).

Дополнение: Собственно, такой подход — это все, что вам нужно, если класс не имеет свойств (то есть вы просто экспортируете функции в ООП стиле). Если свойства есть, вы можете ограничить доступ к ним с помощью модулейAttribute::Constant, Scalar::Readonly и других.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]