作成プロパティによって暗黙的に指定された派生クラスを持つオブジェクトを作成するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1000681

質問

次のパターンを探しています。 (私はPerlで作業していますが、言語は特に重要ではないと思います。)

親クラスFoo、および子Bar、Baz、Bazza。

Fooを構築するためのメソッドの1つは、文字列を解析することです。その文字列の一部は、作成するクラスを暗黙的に指定します。たとえば、「http:」で始まる場合はBarですが、そうではなく「[Date]」が含まれている場合、Bazは気に入っています。

今、Fooがそのすべての子について、そしてどの文字列がBarで、Bazが何であるかなどを知っている場合、適切なコンストラクタを呼び出すことができます。ただし、基本クラスにはその子についての知識はないはずです。

私が欲しいのは、Fooのコンストラクターが子を順番に試すことができるようにすることです。

一般的な場合、文字列を受け入れる子が複数存在する可能性があるため、この問題は明確に定義されていないことがわかります。したがって、それらの呼び出し順序は重要です。文字列の1つだけが子文字列を好きになるようなものです。

私が思いついたのは、初期化時に子クラスが基本クラスに「登録」することです。これにより、コンストラクターのリストを取得し、それらをループします。しかし、私が見逃しているより良い方法はありますか?

サンプルコード:

package Foo;

my @children;

sub _registerChild
{
  push @children, shift();
}

sub newFromString
{
  my $string = shift;
  foreach (@children) {
    my $object = 

次のパターンを探しています。 (私はPerlで作業していますが、言語は特に重要ではないと思います。)

親クラスFoo、および子Bar、Baz、Bazza。

Fooを構築するためのメソッドの1つは、文字列を解析することです。その文字列の一部は、作成するクラスを暗黙的に指定します。たとえば、「http:」で始まる場合はBarですが、そうではなく「[Date]」が含まれている場合、Bazは気に入っています。

今、Fooがそのすべての子について、そしてどの文字列がBarで、Bazが何であるかなどを知っている場合、適切なコンストラクタを呼び出すことができます。ただし、基本クラスにはその子についての知識はないはずです。

私が欲しいのは、Fooのコンストラクターが子を順番に試すことができるようにすることです。

一般的な場合、文字列を受け入れる子が複数存在する可能性があるため、この問題は明確に定義されていないことがわかります。したがって、それらの呼び出し順序は重要です。文字列の1つだけが子文字列を好きになるようなものです。

私が思いついたのは、初期化時に子クラスが基本クラスに「登録」することです。これにより、コンストラクターのリストを取得し、それらをループします。しかし、私が見逃しているより良い方法はありますか?

サンプルコード:

<*>->newFromString(@_) and return $object; } return undef; } package Bar; our @ISA = ('Foo'); Foo::_registerChild(__PACKAGE__); sub newFromString { my $string = shift; if ($string =~ /^http:/i) { return bless(...); } return undef; }
役に立ちましたか?

解決

モジュールでこれを実装できます。 :プラグイン可能?これにより、登録の必要がなくなります。

私が以前に取ったアプローチは、Module :: Pluggableを使用して子モジュールをロードすることでした(これにより、単に子モジュールを作成してインストールするだけで新しい子モジュールを追加できました)。各子クラスには、祝福されたオブジェクトまたはundefを返すコンストラクタがあります。オブジェクトを取得するまでプラグインをループし、それを返します。

次のようなもの:

package MyClass;
use Module::Pluggable;

sub new
{
    my ($class, @args) = @_;
    for my $plugin ($class->plugins)
    {
       my $object = $plugin->new(@args);
       return $object if $object;
    }
}

Class:Factory があります同様に、それはあなたのニーズのために少し上かもしれません。

他のヒント

単一のクラスを基本クラスとファクトリーの両方にしようとしているようです。しないでください。 2つの別個のクラスを使用します。このようなもの:

package Foo;

package Bar;
use base 'Foo';

package Baz;
use base 'Foo';

package Bazza;
use base 'Foo';

package Factory;
use Bar;
use Baz;
use Bazza;

sub get_foo {
    my ($class, $string) = @_;
    return Bar->try($string) || Baz->try($string) || Bazza->try($string);
}

そして次のように使用します:

my $foo = Factory->get_foo($string);

これにより、基本クラスは子クラスについて知る必要がなく、ファクトリのみが知る必要があります。また、子クラスもお互いについて知る必要はありません。どの子クラスをどの順番で試すかを詳細に知る必要があるのはFactoryだけです。

既存の子クラスを検索するFooクラスに任意のルックアップアルゴリズムを実装できます。たぶん、子クラス、またはあなたが考えるかもしれない他のメカニズムで提供される設定ファイルに基づいています。

Fooクラスは、実行時に既存のクライアントクラスを検出し、順番に呼び出します。

さらに、検索結果をキャッシュして、既に説明したレジストリソリューションに近づけることができます。

チリデンに関する情報が含まれていない親クラスについてのコメントと、クラス自体に子クラスの適合性を確立するタスクを委任する方法についてコメントをとる場合、おそらく親クラスからクラス選択を除外するのが正しいでしょうこのタスクのシングルトンを作成します。

少なくともそれは私の好みです...これから、現在の親クラス(おそらく子クラスに共通の機能を持っている)は、おそらく抽象またはインターフェースになります。

シングルトンは、すべての子クラスの構築とその分布を管理できます(機能していない場合はクローンしますか?)...さらに、子クラスを分離を促進するために別のdllに移動できます。

それは直接的な解決策ではありません。 あなたがここにいるのと同じように、私は過去にシングルトンのクラスのリストを管理することでこれを行いました。シングルトンの背後にある考え方は、高価なリフレクションを使用する場合、一度だけ実行すればよいというものです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top