2

HTML::FormHandlerを使用しています。field_name_spaceそれを使用するには、それからサブクラス化することを想定しており、 orなどのいくつかの属性をオーバーライドできますattribute_name_space

ただし、現在、すべてが拡張されているフォーム、HTML::FormHandlerまたはその DBIC ベースのバリアントHTML::FormHandler::Model::DBICが多数あるため、これらのオーバーライドされた属性が何度も繰り返されています。

それらをロールに入れようとしましたが、+attrロールでは表記がサポートされていないというエラーが表示されます。けっこうだ。

この繰り返しをなくす最善の方法は何ですか? おそらくサブクラス化を考えましたが、 と に対して 2 回実行する必要がありますHTML::FormHandlerHTML::FormHandler::Model::DBICさらに、サブクラス化は通常、代わりに Roles を使用したほうがよいというのが一般的な考えだと思います。

更新:例を挙げるのは良い考えだと思いました。これは私が現在行っていることであり、コードの繰り返しが含まれます。ご覧のとおり、1 つのフォームが別の親クラスを使用しているため、属性オーバーライドを入れるために 1 つの親クラスを作成することはできません。2 つ作成する必要があり、冗長性も追加されます。

package MyApp::Form::Foo;

# this form does not interface with DBIC
extends 'HTML::Formhandler';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...

package MyApp::Form::Bar;

# this form uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...

package MyApp::Form::Baz;

# this form also uses a DBIC object
extends 'HTML::Formhandler::Model::DBIC';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

...
4

3 に答える 3

4

まず第一に、ロールはクラスに構成され、サブクラス化とは何の関係もありません。サブクラスは、親 (または複数の親) を拡張する完全なクラスですが、私の経験では、可能な場合は多重継承を避ける必要があります。ロールは動作の一部、またはクラスに適用できる部分的なインターフェイスです。その後、ロールはクラスを直接変更します。一般に、新しいクラスは作成されません。

したがって、継承と役割の構成は、実際には 2 つの異なるものであり、2 つの異なる種類の設計です。したがって、一方を他方と単純に交換することはできません。どちらも異なる設計上の意味合いを持っています。

私の戦略HTML::FormHandlerは、必要なフォームごとに実際のサブクラスを作成し、再利用したいフォームのさまざまな動作をロールに入れることでした。

この質問 (必要な拡張機能をクリーンで正気な方法で実装する方法) は、実際の設計を知らなければ答えられないと思います。

更新:あなたの言いたいことはわかりますが、それはトリッキーなケースです。HTML::FormHandler主に継承による拡張を対象としています。HTML::FormHandlerしたがって、最良の戦略は実際には 2つのサブクラスを持つことだと思いますHTML::FormHandler::Model::DBIC。最初は面倒に思えますが、長期的には別の設定が必要になる場合があります。実際の構成 (デフォルト値) を繰り返さないようにするために、次のことを試してみます (この例は、DBIC を使用しない単純な HFH です)。

package MyApp::Form;
use Moose;
use namespace::autoclean;

extends 'HTML::FormHandler';
with 'MyApp::Form::DefaultSettings';

# only using two fields as example
for my $field (qw( html_prefix field_traits )) {
    has "+$field", default => sub {
        my $self   = shift;
        my $init   = "_get_default_$field";
        my $method = $self->can($init)
          or die sprintf q{Class %s does not implement %s method}, ref($self), $init;
        return $self->$method;
    };
}

1;

計算に別の属性の値が必要な場合は、属性を遅延させる必要があることに注意してください。上記の基本クラスは、初期化された値を見つけるためにフックを探します。両方のクラスでこれを行う必要がありますが、デフォルトのサブルーチン生成を、ライブラリからインポートする関数に入れることができます。上記では、デフォルト値を変更するために属性を直接操作する必要がなくなったため、上記で呼び出したロールにそのようなものを配置できますMyApp::Form::DefaultSettings

package MyApp::Form::DefaultSettings;
use Moose::Role;
use namespace::autoclean;

sub _build_html_prefix  { 1 }
sub _build_field_traits { ['MyApp::Form::Trait::Field'] }

1;

この方法により、役割がデフォルト値の構築に影響を与えることができます。たとえば、上記のロールに基づいて、値を で変更するロールを持つことができますaround

非常に単純ですが、私の意見ではちょっと醜い方法BUILDもあります。値を変更するメソッドをロールに提供させることができます。これは最初は非常に単純で簡単に思えますが、拡張性/柔軟性とシンプルさをトレードオフしています。シンプルに機能しますが、非常に単純なケースでのみ機能します。通常、Web アプリケーションのフォームの量はかなり多く、ニーズは非常に多様であるため、より柔軟なソリューションを使用することをお勧めします。

于 2010-08-03T15:00:37.060 に答える
1

のコードHTML::FormHandler::Model::DBICは、この状況を支援するために実際には Moose トレイトにあります。基本クラスから継承でき、DBIC モデルを使用するフォームで次のことができます。

with 'HTML::FormHandler::TraitFor::Model::DBIC';
于 2013-02-05T17:50:08.477 に答える
0

共通のデフォルトのオーバーライドを 1 つのクラスに配置し、次にカスタマイズしたコードを別のクラスに配置する多重継承を使用するこの方法はどうでしょうか?

package MyApp::Form;

use Moose;
extends 'HTML::Formhandler';

has '+html_prefix'          => (default => 1); 
has '+field_traits'         => (default => sub { ['MyApp::Form::Trait::Field'] }); 
has '+field_name_space'     => (default => 'MyApp::Form::Field');
has '+widget_name_space'    => (default => sub { ['MyApp::Form::Widget'] }); 
has '+widget_wrapper'       => (default => 'None');

package MyApp::Form::Model::DBIC;

use Moose;
extends 'MyApp::Form', 'HTML::Formhandler::Model::DBIC';

# ... your DBIC-specific code

これで、必要に応じて MyApp::Form または MyApp::Form::Model::DBIC から派生できます。

于 2010-08-03T16:41:18.973 に答える