Делегирование по унаследованному объекту - PullRequest
1 голос
/ 26 марта 2012

Вот наша текущая реализация:

У нас есть базовый класс - Coew Device.Есть много классов, которые унаследованы от этого класса базового устройства - с определенной реализованной функцией.Эти производные классы являются базовыми классами для других типов устройств.Проще говоря, это похоже на следующую структуру:

Базовое устройство -> Устройства LevelA ==> Устройства LevelB .... ==> Устройства Level Z

Для работы на этих устройствах конечного уровня,конечное приложение создает объект этого устройства и начинает вызывать API, доступные с уровня устройства Z до уровня root.

например,

my $iPhone = new DeviceLevelZ (NAME => 'iPhone');

В настоящее время для обработки подпрограммы, которая не реализована ни в одном из путей дерева, AUTOLOAD используется в базовом классе базового устройства.Итак, AUTOLOAD в базовом классе - Core Device - выполняет необходимое действие на основе подпрограммы, вызываемой из конечного приложения.

Теперь мы планируем уйти из AUTOLOAD и хотели бы принять делегирование с использованием класса Конвея:Модуль делегирования.

Чтобы реализовать это, я обновил базовый класс Core Device, определив делегирование следующим образом:

use Class::Delegation
    send => 'getFoo',
    to => sub { print "Hello Worlld!! I am foo\n" },
;

Но когда я вызываю sub getFoo из объекта устройства, он не делегирует этому delagtor.

Вот небольшая программа, упоминающая то же поведение:

my $device = new DeviceLevelZ();
$device->get();
$device->getDelegation();

package ResourceX;
use Class::Delegation
    send => 'getDelegation',
    to => sub { print "Hello Worlld!! I am foo\n" },
;
sub new
{
    my ($class, %args) = @_;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub get
{
    print "I am a resource\n";
}

package DeviceLevelZ;
use base qw(ResourceX);

sub new
{
    my ($class, %args) = @_;
    my $self = $class->SUPER::new(%args);
    bless $self, $class;
    return $self;
}

1;

1 Ответ

4 голосов
/ 26 марта 2012

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

Я думаю, что вам не хватает указания sub для точки делегирования.Предполагается вернуть делегата.Damian sez :

Подпрограмма может также возвращать ссылку на объект, и в этом случае подпрограмма делегируется этому объекту (а не атрибуту текущего объекта),Это может быть полезно, когда фактическая цель делегирования более сложна сложна , чем просто прямой атрибут.[выделение мое]

Итак, если вы добавите в свой код, скажем, такой пакет:

package DoesDelegation;
our $Delegate = bless {}, __PACKAGE__;

sub getDelegation {
    say 'You just called me!';
}

И вы измените подпрограмму делегирования следующим образом:

    ...
    to => sub { 
    print "Hello Worlld!! I am foo\n";
    $DoesDelegation::Delegate;
    },

Вы не увидите неудачного делегирования - потому что теперь вы передали назад что-то, что может обработать сообщение 'getDelegation'

Кроме того, чтобы дать вам понимание того, что происходит в фоновом режиме:Если вы измените свой код следующим образом:

use Class::Delegation
    send => 'getDelegation',
    to => sub { 
    use Data::Dumper;
    warn "In delegate \@_ :\n", Dumper( \@_ ), "\n";
    warn "\$1='$1'\n\$2='$2'\n";
    print "Hello Worlld!! I am foo\n";
    $DoesDelegation::Delegate;
    },

Вы увидите это:

In delegate @_ :
$VAR1 = [
          bless( {}, 'DeviceLevelZ' ),
          'getDelegation'
        ];

$1='DeviceLevelZ::'
$2='getDelegation'

Таким образом, есть два источника данных.В @_ вы получаете 1) открытый объект и 2) имя метода.Принимая во внимание, что вы получаете другие данные в $1 и $2, которые являются полным именем метода, разделенного на пакет (имя тайника?) И имя.

A Предложение для Class::Delegator

Если у вас такое сложное делегирование, вы можете использовать подпрограмму.Но я не вижу этого в вашем описании.Если у вас нет чего-то такого сложного, то я рекомендую урезанную версию Дэвида Уилера Class::Delegator, где я обнаружил, что это правда, при кредитовании модуля Конвея:

Блестящий модуль Дамиана Конвея делает в десять раз больше, чем этот - и в десять раз медленнее.

Я также рекомендую использовать декларативную структуру use оператор для отправки ваших делегаций, вместо того, чтобы пытаться делегировать подчиненному, который направляет его соответствующему делегату, как вы, похоже, делаете здесь.

Если у вас имеется делегат для обработки getFoo, тогда вместо этого сделайте следующее:

...
send => 'getFoo', to => '{foo_getter}'

Moose

Третий ипоследний способ сделать это - Moose Делегирование :

package Website;
use Moose;

has 'uri' => (
    is      => 'ro',
    isa     => 'URI',
    handles => [qw( host path )],
);

Таким образом, при указании делегатов для агрегатного объекта, вы указываете делегирование в handles параметр.

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