委托超过继承的对象

时间:2012-03-26 09:34:33

标签: perl delegates

这是我们目前的实施:

我们有一个基类 - Coew Device。有许多类继承自此Core Device类 - 已实现特定功能。这些派生类是其他类型设备的基类。简单来说,它就像以下结构:

核心设备 - > LevelA设备==> LevelB设备.... ==> Z级设备

要处理这些叶级设备,最终应用程序会创建此设备的对象,并开始调用从设备级别Z到根目录的API。

e.g。

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

目前,为了处理未在任何树路径中实现的sub,AUTOLOAD用于Core Device基类。因此,基类的AUTOLOAD - 核心设备 - 根据从最终应用程序调用的子进行必要的操作。

现在,我们计划远离AUTOLOAD,并希望使用Conway的Class :: Delegation模块来使用该代表团。

为了实现这一点,我通过定义像这样的委托

更新了核心设备基类
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 个答案:

答案 0 :(得分:4)

它正在尝试委派,但您要发回print的结果。由于1没有受到祝福,因此您无法在其上调用方法,并且授权在此时失败。

我认为您错过了为委派点指定sub的意义。它应该返回代表。达米安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中获得了其他数据,这是按包(存储名称?)和名称拆分的方法的全名。

Class::Delegator

的建议

如果你有一个复杂的代表团,那么你可以使用一个sub。但我在你的描述中没有看到。如果你没有有一些复杂的东西,那么我推荐David Wheeler的精简版Class::Delegator,我在这里得到了Conway的模块,我认为这是真的:

  达米安康威的精彩模块比这个模块做了十倍 - 并且速度慢了十倍。

我还建议您使用use语句的声明性结构来分派您的代理,而不是尝试委托给将其路由到正确的委托的子,就像您在此处所做的那样。

如果您代表处理getFoo,那么请执行此操作:

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

驼鹿

第三种也是最后一种方法,Moose Delegation

package Website;
use Moose;

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

因此,在指定聚合对象的委托时,可以在handles参数中指定委托。