Как справиться с этой ситуацией в объектно-ориентированном Perl - PullRequest
0 голосов
/ 21 июня 2010
package a::b::c:d

my $res =  a::b::c:e->new(); # i am doing like this
# is there any othere to do this

sub new {
...
 my $self = { 
     #result = a::b::c:e->new();
  }
}

sub test {
}

sub test2 {
}


1;

package a::b::c:e

sub new {
...
}

sub testresult {
}
1;

Мой вопрос:

  • как инициализировать модуль e в d в самом новом, создавая каждую функцию и

  • как использовать это, чтобы сохранить некоторые результаты в e:testresult

Ответы [ 2 ]

2 голосов
/ 21 июня 2010

Существует две стратегии: либо изучить таблицу символов для инициализации при создании, либо использовать AUTOLOAD и выполнить тестирование с помощью can. AUTOLOAD может быть сложнее, так как вам приходится иметь дело со случаем, когда метод отсутствует:

sub AUTOLOAD {
    my $self = shift;

    my $method = $AUTOLOAD;
    $method =~ s/.*://;   # strip package name

    if ( $self->{'result'}->can($method) ) {
        return $self->{'result'}->$method(@_);
    } else {
        croak "Unknown method : $method";
    } 
}  

Но трюк с таблицей символов хрупок, так как, если они используют наследование, вы не увидите унаследованные методы и без перехода на @ISA. (и даже если это не так - они могут начать использовать наследование в будущем, что приведет к поломке)

...

Как правило, когда вы пытаетесь скопировать интерфейс другого модуля, у вас есть случай наследования, поэтому вы можете спросить себя, каковы отношения между ::d и ::e:

  • a::b::c::d является a::b::c::e
  • a::b::c::d использует a::b::c::e

Если это отношение типа "отношения", оно обычно лучше подходит для наследования (хотя у вас могут быть обертки вокруг каждого из методов, и вам все равно придется пройти через все это упражнение). Если это отношение использует, скорее всего, вы не хотите наследовать от каждого последнего метода, который у них есть, и можете просто жестко закодировать список (хотя список может измениться, если обновленный класс обновится)

foreach my $method ( @list_of_methods_to_copy ) {
    *{$method} = sub {
        my $self = shift;
        return $self->{'results'}->$method(@_);
    }
}
0 голосов
/ 21 июня 2010

При условии, что вы не ищете наследования между двумя классами, мне кажется, что вы можете использовать Class::Delegator для создания своего класса.Таким образом, вы можете создать процедуры делегирования, добавив в a::b::c::d следующее.

use Class::Delegator send => 'testresult', to => '{result}';

Но вам все равно придется исправить конструктор:

my $self 
    = bless { 
        result => a::b::c::e->new()
    }, $class_name
    ;
return $self;

После этого у вас будет поле '{result}' для делегирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...