私はさまざまなデザインパターンについて学んでおり、この特定のパターンを理解する上で不可欠な部分が欠けていると強く感じています。
私が閲覧したすべてのWebサイトとGoFの本には、クローンメソッドがあります。私の理解では、オブジェクトのさまざまなバージョンが必要なときに複製できるオブジェクトのタイプがありますが、(Javaのように)「new」コマンドを使用して各オブジェクトを手動で作成する必要はありません。これにより、具体的な実装を隠すことができます。したがって、クローンを作成するときは、クローンを少し調整して、そのオブジェクトを最初に作成する方法を難しい方法で知らなくても、必要なものにすることができます。これは私の考えは正しいですか?
また、これによりサブクラス化が減り、その後、作成する必要のあるクラスの数が減ると言われています。この部分はよくわかりません。誰かが私がこれを理解するのを手伝ってもらえますか?
私の最後の質問は、抽象ファクトリ(またはファクトリメソッド)パターンについてです。これらのファクトリパターンとプロトタイプパターンは、新しいオブジェクトの作成時に具体的な実装を隠そうとしているように感じます。どちらかを選択するのはいつですか?
皆さん、ありがとうございました!
プロトタイプは、元のオブジェクトとは異なるクローンオブジェクトになります。オリジナルの状態は、クローン作成時のクローンと同じです。その後、各オブジェクトは状態変化を受ける可能性があります。これは、オリジナルをコピーしてから、いくつかの場所でコピーを変更するのと似たようなものと考えることができます。
例
利点
MemberwiseClose()
をオーバーライドする必要があることに注意してください。いつ使用するか
ファクトリパターンとの比較
プロトタイプパターンを使用すると、オブジェクトは、クラスや作成方法の詳細を知らなくても、カスタマイズされたオブジェクトを作成できます。したがって、この側面は、ファクトリメソッドパターンによく似ているように見えます。これらのパターンの両方で、クライアントは、自身の構造について何も知らなくても、派生クラスオブジェクトを作成できます。
ただし、2つのパターンの違いは、Factory Method
の場合、存在しないオブジェクトタイプの1つのオブジェクトをfresh creation
として作成することに集中するという事実です(Creatorクラスの正確なサブタイプを理解することにより)。 Prototype
パターンは、クラス自体、特にself duplication
アクションの派生クラスを使用します。
このパターンでは、クライアント(またはコンシューマー)は、クラス階層から特定のタイプのオブジェクトを作成者(またはファクトリ)に要求します。ファクトリクラスのCreatorメソッドは、特定のオブジェクトの作成を派生クラスに委任し、クライアントから要求されたタイプのクラスのオブジェクトを返します。本質的に、クラス階層の複数のオブジェクトを作成するための単一の連絡先があります。
これは、航空券カウンター(コントローラー)に行き、チケットの種類(ファーストクラス、エグゼクティブ、エコノミー)を選択してチケットを要求することと考えることができます。オブジェクト表現では、ファーストクラスとエコノミーチケットの両方が基本チケットクラスから派生している場合でも、ユーザーはチケットがどのように生成されるかを気にしません。
いつ使用するか
特定のファクトリクラスがすでに存在します。ただし、ファクトリの方法は少し異なります。各メソッドはインスタンスを生成できます。クライアントは適切な方法を選択してインスタンスを取得できます。
[〜#〜] mvc [〜#〜] ベースの完璧な建築設計の例をとると、クライアントはビジネスコントローラークラスになり、コンクリート製品はすべてビジネスエンティティになります。ファクトリは補助(ヘルパー)コントローラーです。これらは、ビジネスコントローラーからの要求に関連して機能します。
いつ使用するか
見た目だけでプロトタイプパターンができました。
MineCraftを作成していて、さまざまな種類のブロック(土、石など)ごとにプロトタイプパターンを使用しているとします。すべてのプロトタイプオブジェクトは実際には同じクラスBlock
ですが、各オブジェクトには異なるプロパティが設定されているため、次のように表示と動作が異なります。
_prototypes.dirt = new Block;
prototypes.dirt.texture = new Image("dirt.jpg");
prototypes.dirt.hardness = 1;
prototypes.stone = new Block;
prototypes.stone.texture = new Image("stone.jpg");
prototypes.stone.hardness = 9;
_
したがって、_new DirtBlock
_または_new StoneBlock
_を記述する場所をサブクラス化する代わりに、prototypes.dirt.clone()
またはprototypes.stone.clone()
を記述します。サブクラス化は必要ありませんが、必要に応じてサブクラス化するオプションがあります。
ファクトリパターンの代わりにプロトタイプパターンを選択する場合については、2つの状況が考えられます。
プロトタイプのリストを反復処理することはできますが、抽象ファクトリのすべてのメソッドを反復処理することはできません^。上記のコードから続けると、次のようなランダムなブロックを作成できます。
prototypes.allValues().objectAtIndex(Rand() % prototypes.size()).clone();
ファクトリメソッドを使用してブロックを作成している場合、ランダムなブロックを取得するのは困難です。
オブジェクトの作成に費用がかかるが、コピーに費用がかかる場合は、プロトタイプパターンの方が効率的です。たとえば、次のファクトリメソッドを使用します。
_Image loadUserImage() {
//loads from disk. will be slow
return new JPEGImage("path/to/user/image.jpg");
}
_
このメソッドが繰り返し呼び出される場合は、次のようなプロトタイプを使用する方が効率的です。
_Image loadUserImage() {
//copy in memory. will be fast
return userImagePrototype.clone();
}
_
^使用している言語に応じて実際にメソッドを反復処理できるため、これは白い嘘ですが、配列を反復処理する方が、リフレクション/イントロスペクションよりも複雑ではないため、おそらくより良い解決策です。
プロトタイプを使用することの効率の向上は、私の心の中で疑わしいです。ほとんどの言語では、cloneメソッド自体がnewの呼び出しを実行して、それ自体の新しいオブジェクトインスタンスを構築するため、効率は向上しません。
プロトタイプパターンを使用することで私が見る唯一の利点は、利便性の1つです。クローンを使用すると、オブジェクトの正確なコピーが得られるため、新しいオブジェクトの属性を自分で同じ値に設定する必要がなくなり、苦労する可能性があります。ディープコピー付き。