#perl #oop #polymorphism
#perl #ооп #полиморфизм
Вопрос:
Кажется, существует несколько способов сделать полиморфизм в Perl, но все они кажутся мне «халтурными». Я несколько новичок в Perl, поэтому могу просто неправильно интерпретировать его, но я нахожу, что большинство примеров делают ваш код слишком неразборчивым и противоречивым.
Допустим, у вас есть класс виджетов, который содержит некоторые данные и методы, необходимые всем виджетам. Существует также несколько типов виджетов (например, календарь, расписание и т. Д.). И они должны взаимодействовать друг с другом (через родительский класс контейнера).
Стоит ли играть с пространством имен и превращать виджет в прототип?
Должен ли я давать каждому виджету ссылку на объект (один из типов) при создании экземпляра?
Просто забудьте о том, что типы являются объектами, и сделайте widget большим классом, в котором для каждого экземпляра используется только несколько методов в зависимости от того, какой тип установлен. Что-то еще?
Я родом из C / C , и мне трудно определиться с моделью программирования на Perl.
Кроме того, у меня нет строгих требований к безопасности типов или закрытым членам. Проект представляет собой веб-приложение среднего размера с несколькими разработчиками, и переносимость на другие проекты не является приоритетом. Хотя было бы полезно простое расширение без необходимости расшифровывать хаки Perl.
Комментарии:
1. Что вы подразумеваете под «прототипом»? Вы проверили
Moose
?2. Стандартный способ вызова вызывающих методов (
$o->method()
) заставляет их вести себя как виртуальные методы. Полиморфизм свободен. О каких взломах ты говоришь?3. Я не большой сторонник Perl-ООП, он существует, он функционален, но это не то, для чего нужен Perl. Это все равно что использовать отвертку в качестве молотка. Это язык сценариев оболочки, который можно использовать для написания сценариев общего назначения. Я удивлен, что вы создаете новое (?) веб-приложение на Perl.
4. @EugeneK, ерунда! С момента появления Moose у Perl был OO-фреймворк, который оставляет любой другой основной язык программирования в пыли.
5. @EugeneK, Perl OO может показаться немного более неуклюжим, чем чистый OO-язык, такой как Java, но он занимает определенное место в языке. «Язык сценариев оболочки», на мой взгляд, также является недостатком. Рассмотрим только DBI, Win32 :: OLE или Excel :: Writer :: XLSX, и представьте их без возможностей OO.
Ответ №1:
Подход «Современный Perl», вероятно, заключается в определении Widget
как роли. Роль можно рассматривать как подобную mixin, интерфейсу или абстрактному базовому классу. Сделайте это с помощью Moose::Role или одной из его более легких альтернатив (Moo::Role, Role::Tiny).
{
package Widget;
use Moo::Role;
sub some_common_method {
my $self = shift;
...;
}
sub another_common_method {
my $self = shift;
...;
}
# Here we're indicating that all Widgets must
# have a method called yet_another_common_method,
# but we're not defining how that method should
# be implemented.
requires "yet_another_common_method";
}
Теперь вы можете создать класс, который выполняет эту роль:
{
package Calendar;
use Moo;
with "Widget";
# Here's a member variable.
has year => (is => "ro", required => 1);
# Widget requires us to implement this.
sub yet_another_common_method {
my $self = shift;
...;
}
# We can override Widget's implementation
# of this method.
sub some_common_method {
my $self = shift;
...;
}
# We can install hooks ("method modifiers")
# to Widget's methods.
before another_common_method => sub {
my $self = shift;
print STDERR "Calendar ", $self->year, ": another_common_method() was called.n";
};
}
И еще:
{
package Schedule;
use Moo;
with "Widget", "Editable";
sub yet_another_common_method {
my $self = shift;
...;
}
}
И используйте классы:
my $calendar = Calendar->new( year => 2014 );
my $schedule = Schedule->new;
my @widgets = ($calendar, $schedule);
for (@widgets) {
$_->some_common_method if $_->does('Widget');
}
Комментарии:
1. Эй, я заметил, что вы вкладываете свои пакеты
{}
в. Делает ли это что-то, о чем я должен знать?2. Если вы определяете несколько пакетов в одном файле, это может быть полезно для предотвращения, например, утечки лексических переменных из одного пакета в другой. Теперь иногда (редко) вам действительно захочется , чтобы была лексическая переменная, доступная для всех пакетов, определенных в файле, и в этом случае вы бы определили эту переменную вне всех
{ }
битов. Это означает, что он будет выделяться визуально, что, по-видимому, хорошо для такой переменной! Конечно, в большинстве случаев люди определяют один пакет для каждого файла, что делает этот вопрос спорным.