2011-08-09 27 views
2

変数でcoderefsを束縛するのは意味がありますが、完全に壊れたOODを使用しているコードでは悩んでいます。基本的には、機能コードを書いていますが、ステートフルなものをカプセル化するためにいくつかのOOスタイルの構造に頼っています。は本当にとなります。それは主に国家のない機能です。Perl:型制約のないクラス::構造

これに対してMooseを使用すると、ときどき自動ライフルを使用している後期同僚のようになります。だから私を救いなさい、 'すべてのパープルオップは今使ってはいけない!'マントラ。

私は入札を行うために良いol 'blessed-hashrefクラスを実行しましたが、アクセサーコードを書くことは苦痛であり、非標準モジュールでは本質的に非常に些細なもの仕事。

http://perldoc.perl.orgのページをシャッフルした後、私はOO属性の構築を容易にするコアモジュールであるClass :: StructとObject :: Accessorを見つけました。パーフェクト、私は。しかし...

Object :: Accessorは完璧なチケットのようでしたが、コンストラクタでmk_accessorサブクラスを使用していましたが、コンパイル時Class :: Structを使用するほど優雅ではありませんでした私のために私のデフォルトのコンストラクタを書いています。全体として、私はClass :: StructをObject :: Accessorに優先させたのは、少しだけ定型文を許可し、より宣言的な構文を持っていたからです。

些細な例を使用して比較し、場合にあなたが迷っている:

使用してクラス::構造体:オブジェクトを使用した

#!/usr/bin/perl 

use 5.014; 
use autodie; 
use strict; 
use warnings; 

package Account { 
    use Class::Struct 
     first_name => '$', 
     last_name => '$', 
     age_in_years => '$', 
     activated => '$', 
     ; 

    sub formatted { 
     my ($self_ref) = @_; 
     return sprintf 
      "First name: %s\n" . 
      "Last name: %s\n" . 
      "Age in Years: %d\n" . 
      "Activated: %s", 
      $self_ref->first_name, 
      $self_ref->last_name, 
      $self_ref->age_in_years, 
      $self_ref->activated || 'No' 
      ; 
    } 
} 

my $account = Account->new; 

$account->first_name('Tom'); 
$account->last_name('Smith'); 
$account->age_in_years(16); 
$account->activated('Yes'); 

say $account->formatted 

::アクセサ:本当に

use 5.014; 
use autodie; 
use strict; 
use warnings; 

package Account { 
    use base 'Object::Accessor'; 

    sub new { 
     my ($type) = @_; 
     my $self = bless { }, $type; 
     $self->mk_accessors(qw(first_name last_name age_in_years activated)); 
     return $self; 
    } 

    sub formatted { 
     my ($self_ref) = @_; 
     return sprintf 
      "First name: %s\n" . 
      "Last name: %s\n" . 
      "Age in Years: %d\n" . 
      "Activated: %s", 
      $self_ref->first_name, 
      $self_ref->last_name, 
      $self_ref->age_in_years, 
      $self_ref->activated || 'No' 
      ; 
    } 
} 

my $account = Account->new; 

$account->first_name('Tom'); 
$account->last_name('Smith'); 
$account->age_in_years(16); 
$account->activated('Yes'); 

say $account->formatted; 

を、両方の完全に受け入れられますが、前者はかなり清潔なIMOです。私が知りたいのは、タイプ制約を指定せずにClass :: Structを使用できますか?

私はそれらを使用している文脈でそれらを必要としませんが、型制約を指定することなくアクセッサを追加することはできません。不必要な型チェックのせいでパフォーマンスが失われることは間違いありません。

これができない場合は、Object :: Accessorに固執します。しかし、型制約のないアクセサはClass :: Structで可能ですか?

答えて

1

私はタスクに対してClass::Structを好んでいます。私は通常、スカラーだけを使用しています、彼らは妥当性検査をしていないし、(配列参照やハッシュリファレンスのような)それらに何かを格納することができます。

もう1つの利点は、あなたが選択した構文が、配列がより小さく、より高速にアクセスできることに基づいてオブジェクトを作成することです。劇的なものはありませんが、個のオブジェクトが多い場合は、オブジェクトが役に立ちます。

package Account; 
use Class::Struct 
    map { $_ => '$' } qw(
     first_name 
     last_name 
     age_in_years 
     activated 
     items 
    ); 

package main; 

my $acc = Account->new(
    first_name => 'John', 
    last_name => 'Doe', 
    items  => ['a' .. 'z'] 
); 
+0

アドバイスありがとうございました。 Class :: Structのドキュメントでは、独自のコンストラクタを使用していますが、引数のデフォルト値を指定したいと考えています。私の最初のアイデアは、シンボルテーブルをハックして、Class :: Structで生成されたコンストラクタをstruct_newに移動し、デフォルトの引数を解決した後にstruct_newを呼び出す独自の新しいサブを再定義することでした。もう一つのアイデアは、Class :: Structが生成するものを見て、古いものがしたことを引き継ぐオーバーライドsub newを明示的に記述することですが、引数の検証が追加されています。しかし、以前のアイデアはカプセル化をやや少なくしているようです。より良い方法がありますか? – Louis

+0

@Louis - 私は 'Class :: Struct'のサブクラス化について考えましたが、その動作は' struct'関数内にすべて埋め込まれており、パートごとに簡単に置き換えることはできません。あなたは基本的な実装に依存しないので、以前のアイデアを好むでしょう。 – bvr

+0

シンボルテーブルをハックし、不要な型制約を使用すると、Object :: Accessorを使用するよりははるかに明確な増加は得られませんでした。 hashrefとarrayrefのクラスのパフォーマンスに関して、私はそれを見ていくつもりです:) Object :: Accessorを使って祝福された配列をロールアウトすることもできます。それが特に困難でない場合。 – Louis