【问题标题】:How to declare 2 dependant attributes in Mooseish way?如何以 Mooseish 方式声明 2 个依赖属性?
【发布时间】:2012-08-15 17:57:24
【问题描述】:

在我的对象构造函数中,我有声明同时初始化两个属性:

($self->{token}, $self->{token_start}) = $self->_get_authorized_token();

所以我得到了令牌,它的开始时间在一个声明中。

现在我尝试移植我的模块以使用 Moo(se) 在这里我不知道我应该如何同时设置这两个绑定属性?一些伪代码是这样的:

has qw/token token_start/ => (
    is  => 'rw',
    default => shift->_get_authorized_token(); 
);

但是如何以 Moo(se)ish 方式声明 2 个绑定属性?


编辑。我展示了_get_authorized_token方法的代码,也许会带来一些想法:

sub _get_authorized_token {
    my $self = shift;
    my $postData = { 'apikey' => $self->{key} };
    my $url = $self->{base_url} . '/seller';
    my $xml = $self->_post(url => $url,
                            postdata => $postData,
                        );
    my $ref = XMLin($xml, SuppressEmpty => '' );
    my $time = $ref->{Notification_Datetime};
    my $token = $ref->{Notification_Data}{body}{token};
    return ($token, $time); 
}

【问题讨论】:

    标签: perl moose moo


    【解决方案1】:

    一旦你最终得到两个属性,这些属性基本上链接到你总是同时设置它们的点......答案通常是为此目的创建一个具有两个属性的值对象,然后将相关方法委托给它。所以,像 -

    package MyApp::TokenInfo;
    
    use Moo;
    
    has token => (is => 'ro', required => 1);
    has token_start => (is => 'ro', required => 1);
    
    ...
    
    package MyApp::ThingWithAToken;
    
    use Module::Runtime qw(use_module);
    use Moo;
    
    ...
    
    has token_info => (is => 'lazy', handles => [ qw(token token_start) ]);
    
    sub _build_token_info {
      my ($self) = @_;
      my ($token, $token_start) = $self->_get_authorized_token;
    
      # this is equivalent to:
      #
      #   require MyApp::TokenInfo;
      #   return MyApp::TokenInfo->new(...);
      #
      # but more concise
    
      return use_module('MyApp::TokenInfo')->new(
        token => $token,
        token_start => $token_start
      );
    }
    
    ...
    
    my $thing = MyApp::ThingWithAToken->new(...);
    
    $thing->token; # calls $thing->token_info->token;
    $thing->token_start; # calls $thing->token_info->token_start
    

    所以值对象的存在不需要来自外部的知识,但在内部,您仍然可以将这两个属性绑定在一起,让您的实现将它们作为单个“事物”处理。

    --mst

    【讨论】:

    • SO 注定要失败; mst 已加入!天哪! :-)
    【解决方案2】:

    我不知道有什么方法可以将这两个属性绑定在一起,就像您使用直接哈希分配一样。

    我可能会让两个懒惰的建设者做类似的事情:

    sub _build_token {
      my $self = shift;
      my ($t, $ts) = $self->_get_authorized_token();
      $self->token_start($ts);
      return $t
    }
    

    然后反过来构建 token_start。

    我怀疑你真正想要的是让 token/token_start 成为他们自己对象的一部分。这样你就可以保证两者都被适当地设置在一起。


    我仍然有 2 个依赖属性,我也不能将它们分开。或者重点在哪里?

    我不确定问题是否清楚。在我看来,这两个值似乎属于一起,或者至少 token_start 取决于 token。我更喜欢使用$self->auth->token,这样链接就很清楚了。

    如果您想跳过对“auth”对象的引用,只需使用handles

    【讨论】:

    • 如果它们是它们自己对象的一部分,我该如何将它们组合在一起?在我看来,这个问题仍然存在。
    • $obj->auth_obj(AuthObj->new($self->_get_authorized_token))
    • @Richard_Huxton,在 AuthObj 声明中,我仍然有 2 个依赖属性,我也无法将它们分开。或者重点在哪里?
    • 我没有从你的答案中读出它,但现在我不明白,你的答案与接受的答案基本相同。 +1,谢谢!
    【解决方案3】:

    当面对这种性质的东西——两个或多个属性的值一次生成——并且没有令人信服的理由创建一个小类来处理这个问题时,我通常创建一个属性,然后委托访问器来访问结果。例如:

    has _token_info => (
        traits => ['Hash'],
        is => 'ro',
        isa => 'HashRef',
        builder => '_build__token_info',
        handles => {
            token => [ get => 'token' ],
            token_start => [ get => 'token_start' ]
        },
    );
    
    sub _build__token_info {
    
        # ... whatever needs to be done to get $token{,_start}
        return { token => $token, token_start => $token_start };
    }
    

    这样,当有人第一次访问 token() 或 token_start() 时,会生成并传递令牌和起始值。

    请注意,这种方法通常最适用于始终在类中构建或私有设置的值,而不是在期望构建将 token 和 token_start 传递给 new() 的类时。

    另见http://whitepointstarllc.com/2012/05/simulating-multiple-lazy-attributes/

    【讨论】:

      【解决方案4】:

      我自己也有一些想法。也许我应该使用setter方法而不是使用返回值的方法,它返回一个(如果有的话)值但设置2?像这样:

      sub _set_authorized_token {
          my $self = shift;
          my $postData = { 'apikey' => $self->{key} };
          my $url = $self->{base_url} . '/seller';
          my $xml = $self->_post(url => $url,
                                  postdata => $postData,
                              );
          my $ref = XMLin($xml, SuppressEmpty => '' );
          $self->{token_start} = $ref->{Notification_Datetime};
          $self->{token} = $ref->{Notification_Data}{body}{token};
          return ($self->{token});    
      }
      

      有没有我注意到的一些陷阱?

      【讨论】:

        猜你喜欢
        • 2020-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多