4

私のオブジェクトコンストラクターには、2つの属性を同時に初期化するステートメントがありました。

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

だから私はトークンを手に入れました、そしてそれは1つのステートメントで一緒に始まります。

ここで、Moo(se)を使用するようにモジュールを移植しようとしましたが、これら2つのバインドされた属性を同時に設定する方法がわかりません。いくつかの擬似コードは次のようになります。

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); 
}
4

4 に答える 4

5

基本的に常に同時に設定するポイントにリンクされている2つの属性ができたら、答えは通常、目的のために2つの属性を持つ値オブジェクトを作成し、関連するメソッドをそれに委任することです。だから、のようなもの-

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

したがって、値オブジェクトの存在は外部からの知識である必要はありませんが、内部では、実装がそれらを単一の「もの」として処理できるように、2つの属性を結び付けることができます。

--mst

于 2012-08-25T14:16:00.080 に答える
1

直接ハッシュ割り当ての場合のように、2つの属性をバインドする方法はわかりません。

私はおそらく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つの依存属性を一緒に持っています、私はそれらをそこで分離することもできません。またはポイントはどこですか?

質問からポイントが明確かどうかはわかりません。2つの値は一緒に属しているように見えます。または、少なくともtoken_startはtokenに依存しています。$self->auth->token つながりがはっきりするように使いたいと思います。

ただし、「auth」オブジェクトへの参照をスキップする場合は、ハンドルを使用してください

于 2012-08-20T12:13:21.550 に答える
1

この種の何か(一度に値が生成される2つ以上の属性)に直面し、これを処理する小さなクラスを作成する理由がない場合、通常は1つの属性を作成してから、結果にアクセスするためにアクセサーを委任します。例えば:

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/も参照してください

于 2012-10-12T18:33:05.037 に答える
0

私も自分で考えました。たぶん、戻り値のあるメソッドを使用する代わりに、1つの(もしあれば)値を返すが2を設定するsetterメソッドを使用する必要がありますか?このような:

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});    
}

私が気付いた落とし穴はありますか?

于 2012-08-21T07:57:44.297 に答える