取势 明道 优术

作者为 扶 凯 发表

 


NAME

Moose::Manual::Delegation – 委托属性

 


VERSION

version 2.0401

 


什么是Delegation

Delegation是Moose提供的一个特性,相当于一个代理,你可以创建一个对属性进行操作的代理方法,这在定义一些十分复杂的属性的时候很有效果,同样代码也可以分离的很好,我们只需要知道代理的API,修改属性也可以通过更改代理完成.

使用委托代理的方式,消费者不需要知道一个对象所包含的所有东西,这样就减少一个类的api个数,因为不少接口我们都通过delegation来完成了.

Delegation(委托)通过mapping方法来实现,也就是对方法的映射,甚至我们可以加上自己的别名,我们在后面的代码可以看到.

Delegation另外一个用途就是用来封装那些不是Moose的class,通过委托我们可以尽量利用上moose的特性对这些类进行封装.

 


定义一个映射

Moose提供了大量的可选项来定义委托映射关系.

最简单的就是指定一个方法列表.

  package Website;

  use Moose;

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

根据上面的定义,我们可以调用$website->host,就像我们调用URI对象一样,Moose会帮你调用$website->uri->host,实际上$website不是自动传递host方法,而是调用$website->uri.

同样我们可以定义成hash引用形式的mapping,这样你可以为你所要的方法加上你喜欢的别名.

  package Website;

  use Moose;

  has 'uri' => (
      is      => 'ro',
      isa     => 'URI',
      handles => {
          hostname => 'host',
          path     => 'path',
      },
  );

在上面的代码里,我们已经创建了$website->hostname 方法,这个标签显然比uri的host方法意思更为明确.

上面两种委托的方法是最为常用的,更复杂的一点的我们可以支持正则委托.

  has 'uri' => (
      is      => 'ro',
      isa     => 'URI',
      handles => qr/^(?:host|path|query.*)/,
  );

这个和数组委托有点类似,但是匹配的范围显然更为宽广,你必须为这个属性提供一个isa的参数而且必须是一个可用的class,Moose内部的自省机制会为你找到你想要的方法.

另外,你可以通过role 名称来定义handles

  has 'uri' => (
      is      => 'ro',
      isa     => 'URI',
      handles => 'HasURI',
  );

Moose会根据你所提供的role来决定调用哪些方法.

最后,你还可以提供一个匿名函数引用来生成一个映射,如果你想了解更详细,请参考Moose文档知道更多细节.

 


本地委托

本地委托允许你委托一些标准的perl数据结构,这些数据结构必须是Moose指定的对象.例如:

  has 'queue' => (
      traits  => ['Array'],
      isa     => 'ArrayRef[Item]',
      default => sub { [ ] },
      handles => {
          add_item  => 'push',
          next_item => 'shift',
      },
  )

traits里面的Array特征告诉Moose你想要设置array的辅助特征,Moose将会创建add_item和<next_item>方法,创建的代码如下:

  sub add_item {
      my ($self, @items) = @_;

      for my $item (@items) {
          $Item_TC->validate($item);
      }

      push @{ $self->queue }, @items;
  }

Moose包含了一下特征和本地委托类型.

 


局部套用

这里所要讲述的是如何创建一个方法,并且为方法预设好参数,你可以创建一个局部套用的委托方法set_user_agent

    package Spider;
    use Moose;

    has request => (
        is      => 'ro'
        isa     => 'HTTP::Request',
        handles => {
            set_user_agent => [ header => 'UserAgent' ],
        },
    )

当你调用$spider->set_user_agent('MyClient')的时候,Moose实际上是调用了

    $spider->request->header( 'UserAgent' => 'MyClient' );

注意上面的局部套用,UserAgent是作为第一个参数传递给header方法,而Myclient是第二个参数,这事局部套用参数传递的规则. header方法后面指向的值即为第一个参数.

 


缺失属性.

对于一些不是必须的属性或者是undef的属性,我们可以在这些属性里委托方法,moose在调用委托方法的时候, 如果这个属性没有包含一个对象,就会抛出一个runtime错误.

 


AUTHOR

 斯文牛氓 492003149@qq.com

来了就留个评论吧! 没有评论