デザインパターン入門 | Prototype(プロトタイプ)パターン
「Prototype(プロトタイプ)」パターンは、「インスタンスの複製を作る」デザインパターンです。
「複製元」となるインスタンスを作り、そのインスタンスをプロトタイプとして保存しておき、必要な時に複製を行って利用していきます。
それでは、「Prototype(プロトタイプ)」パターンの詳細について見ていきましょう。
「Prototype(プロトタイプ)」パターンの仕組み
「プロトタイプ」と聞くと「試作品」というイメージを持つ方もいるのではないでしょうか。
今回学ぶ「Prototype(プロトタイプ)」パターンでは、「原型・ひな型」という言葉のほうが適しているかもしれませんが、「インスタンスの複製元」と捉えていただくと良いかもしれません。
現実世界で「原型・ひな型」を考えていくと「金型」がイメージに近いのではないでしょうか。
「樹脂・プラスチック製品」の金型は、製品を作る際に必要となる「原型」と考えることができます。
今回は、「金型(Mold)」を管理するクラスと「製品(Product)」を表すクラスを元にご説明をしていきたいと思います。
今回作成するクラスの構成は下図のようになります。
はじめに、「MoldManager」クラスは下記のようになります。(プログラム言語:Java)
package SamplePrototype; import java.util.HashMap; public class MoldManager { private HashMapproductCollections = new HashMap (); public void registerProduct(String productName, Cloneable product) { productCollections.put(productName, product); } public Product createProduct(String productName) { Product product = (Product) productCollections.get(productName); return product.getClone(); } }
このクラスには、
- productCollectionsフィールド
- プロトタイプを保存するためのハッシュマップ
- registerProductメソッド
- ハッシュマップにプロトタイプを登録する
- createProductメソッド
- 登録されたプロトタイプから「インスタンスの複製」を生成する
が定義されています。
これらの具体的な使い方は、後ほど説明をしていきたいと思います。
そして、「Product」インターフェイスは、下記のようになります。
package SamplePrototype; public interface Product extends Cloneable { public abstract Product getClone(); }
このインターフェイスは「Cloneable」インターフェースを実装していますが、「Cloneable」インターフェースに定義されているメソッドはありません。
「Cloneable」インターフェースは、「cloneメソッド」が使えることを示すためのインターフェースで、このようなインターフェースを「マーカーインターフェース」と呼ぶことがあります。
そして「Product」インターフェイスには、
- getClone
- 「複製したインスタンス」を取得する抽象メソッド
が定義されています。
「Product」インターフェイスを実装した「具象クラス(ConcreteClass)」は、参考例として「プラモデル(PlasticModel)」「自動車部品(CarParts)」の2つを作成しています。
「プラモデル(PlasticModel)」クラスは、下記のようになります。
package SamplePrototype; public class PlasticModel implements Product { private String name; private int price; public PlasticModel(String name, int price) { this.name = name; this.price = price; } public void setPrice(int price) { this.price = price; } @Override public Product getClone() { try { return (Product)clone(); } catch ( Exception e ) { e.printStackTrace(); } return null; } @Override public String toString() { return "このプラモデルの名前は「" + this.name + "」です。価格は" + this.price + "円です。"; } }
そして、「自動車部品(CarParts)」クラスは下記のようになります。
package SamplePrototype; public class CarParts implements Product { private String name; public CarParts(String name) { this.name = name; } public String getPartsName() { return this.name; } @Override public String toString() { return "この自動車部品の名前は【" + this.name + "】です。"; } @Override public Product getClone() { try { return (Product)clone(); } catch ( Exception e ) { e.printStackTrace(); } return null; } }
「getCloneメソッド」の中では、は、「clone」メソッドを実行し、登録されたインスタンスの複製を返すようになっています。
プログラムの実行例は下記のようになります。
package SamplePrototype; public class Main { public static void main(String[] args) { // MoldManagerのインスタンスを生成 MoldManager manager = new MoldManager(); // PlasticModel(プラモデル)のインスタンスを生成 PlasticModel plasticModel = new PlasticModel("タワー", 3800); // PlasticModel(プラモデル)の内容を出力 System.out.println("【plasticModelの出力】"); System.out.println(plasticModel); System.out.println(""); // MoldManagerにインスタンスを登録 manager.registerProduct("タワー", plasticModel); // MoldManagerに登録したオブジェクトのクローンを取得 PlasticModel clonePlasticModel = (PlasticModel)manager.createProduct("タワー"); // 価格の変更 clonePlasticModel.setPrice(5000); // PlasticModel(プラモデル)のクローンの内容を出力 System.out.println("【clonePlasticModelの出力】"); System.out.println(clonePlasticModel); System.out.println(""); // PlasticModel(プラモデル)の内容を出力 System.out.println("【plasticModelの出力(確認用)】"); System.out.println(plasticModel); System.out.println(""); } }
出力結果は、下記のようになります。
【plasticModelの出力】 このプラモデルの名前は「タワー」です。価格は3800円です。 【clonePlasticModelの出力】 このプラモデルの名前は「タワー」です。価格は5000円です。 【plasticModelの出力(確認用)】 このプラモデルの名前は「タワー」です。価格は3800円です。
上記の出力結果を見ると、「plasticModel」と「clonePlasticModel」は別のインスタンスであることがわかりますね。
このようにプロトタイプ(原型)となるインスタンスを登録しておいて、必要に応じて登録されたインスタンスの「クローン(複製)」を作り利用していくデザインパターンが、「Prototype(プロトタイプ)」パターンです。
「何かのインスタンス」を元にインスタンスを作りたい場合に利用できるデザインパターンですので、「どのような仕組みになっているのか」を理解し、プロトタイプパターンが使えるようになっていきましょう。