Practical Python Design Patterns - The Prototype Pattern 編
Implementing the Prototype Pattern(プロトタイプパターンの実装)
プロトタイプパターンでは、継承 (inheritance) よりもコンポジション (composition: 合成/結合) が重視されます。クラスを複数のパーツから構成することで実行時にそれらのパーツの入れ替えが可能となり、システムのテスト性、メンテナンス性に大きな影響を及ぼします。また、実際にインスタンス化されるクラスは実行時に決定され、動的に読み込まれます。プロトタイプパターンのこうした特徴により、クラスの継承/サブクラス化が大きく減少することになります。
新しいオブジェクトを作成する際のこうした複雑な処理はクライアント (このシステムの利用者) からは一切見えません。プロトタイプパターンのこうした機能は非常に優れたものですが、このパターンを採用する本当の利点は「プログラマに対してインターフェースの利用を強制する」ことです。結果的にこれがより良いシステムデザインへと繋がります。
NOTE
循環参照を伴うディープクローニング (deep-cloning) クラスは問題の原因となり得る、ということを意識しておく必要があります。
次章では、浅いコピー (shallow copy) と深いコピー (deep copy) について詳しく取り上げます。
我々がやろうとしていることは、既に手元にあるオブジェクトのコピーを作成する、ということだけです。作成するコピーは「自分が自分であるべきための属性」を備えていなければならず、システム内の他のオブジェクトからは機能的にも独立していなければなりません。
コピー元となるインスタンスは「自身のコピーを作成する」機能を提供する必要があります。オブジェクトのコピーを作成し属性値を適切なものに変更する clone() メソッドといったものです。
プロトタイプパターンを実装す際に必要となる3つのコンポーネントには次のものがあります:
Client (クライアント): プロトタイプに対してクローンの作成を依頼し、結果としてオブジェクトを受け取ります。
Prototype (プロトタイプ): クローンを作成するためのインターフェースを宣言します。
Concrete prototype (プロトタイプ実装クラス): 自分自身のクローンを作成する「実際の操作」を実装します。
(出所 - プロトタイプパターンにおけるコンポーネントツリー: http://radek.io/2011/08/03/design-pattern-prototype/)
我々の RTS ゲームの例で言えば、全ての Barracks では、現在の建物のレベルで生産可能なユニットのタイプ、並びに、レベルから決定される、製造(クローン作成)を依頼するプロトタイプ実装クラスのオブジェクトのリストを保持することになります。そして建物がアップグレードされた際には同時にこのリストもアップグレードすることによって、建物のレベルと製造可能ユニットの整合を保つようにします。
各製造施設では自分のところで製造可能なレベルも考慮したユニットの「プロトタイプオブジェクト」を既に保持しているため、同じユニットを500体製造する場合であっても、残り499体に関しては「クローン作製」を「発注」するだけであり、いちいちストレージにアクセスして必要な属性値をそのたびに取得する必要がありません。
プロトタイプパターンのこうした特徴は、この本でも後ほど取り上げる abstract factory design pattern (抽象的な工場パターン) と異なる点でもあります。
プログラム実行時に製造施設が利用する「プロトタイプオブジェクトのリスト」を変更することで、その建物で製造可能なユニットを動的に変更することが可能になるばかりか、その仕組みの実装において一切「継承 (inheritance): サブクラス化) の必要がありません。我々の製造施設は事実上、プロトタイプマネージャーとして機能します。
プロトタイプパターンのコンセプトは素晴らしいものですが、我々の RTS ゲームにプロトタイプパターンを取り入れる前に、もう1つ重要なコンセプトを確認しておく必要があります...