Index
クラスからインスタンスを生成するのではなく、インスタンスから別のインスタンスを作り出パターンをprototypeパターンという
以下の3つに当てはまるときに使うと良いでしょう
- 種類が多すぎてクラスにまとめられない場合
- クラスからのインスタンス生成が難しい場合
- フレームワークと生成するインスタンスを分けたい場合
複製を可能にするためのインターフェース。
Cloneableインターフェースを継承させることで、cloneメソッドを使って自動的に複製を行うことができるようになります。
ちなみにCloneableインターフェースはoverrideする関数がないのが特徴です。
このようなインターフェースを「マーカーインターフェース」と呼びます
1 2 3 4 5 6 |
package framework; public interface Food extends Cloneable { public abstract void eat(); public abstract Food createCopy(); } |
ManagerクラスはFoodインターフェースを利用してインスタンスの複製を行うクラスです。
クラス内に、Foodクラス、Fishクラスなど具体的なクラス名が出てこないことがポイントです!
これにより、Food,Managerクラスが独立して修正できるようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package framework; import java.util.HashMap; import java.util.Map; public class Manager { private Map<String,Food> showcase = new HashMap<>(); public void register(final String name,final Food prototype) { showcase.put(name, prototype); } public Food create(final String prototypeName) { final Food food = showcase.get(prototypeName); return food.createCopy(); } } |
本来このクラスはなくても良いのですが、後述するFish,Fruitsクラスに全く同じcreateCopy()メソッドを書きたくないので、作りました。
このクラスのポイントはcreateCopy()メソッドで自分自身の複製を作成しているところです。
注意すべきはclone()メソッドはシャローコピーというところです。
ディープコピーをしたい場合はcloneメソッドをオーバーライドして実装する必要があります。
CloneNotSupportedExceptionが投げられるときはClonealeインターフェースを実装していないクラスがcloneメソッドを読んだときです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import framework.Food; public class ConcreteFood implements Food { @Override public void eat(){} @Override public Food createCopy() { Food food = null; try { food = (Food)clone(); }catch(CloneNotSupportedException e) { e.printStackTrace(); } return food; } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Fish extends ConcreteFood { private String m_name; public Fish(final String name) { this.m_name = name; } @Override public void eat(){ System.out.println(String.format("%sを焼いて食べる",m_name)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Fruits extends ConcreteFood { private String m_name; public Fruits(final String name) { this.m_name = name; } @Override public void eat(){ System.out.println(String.format("%sを生で食べる",m_name)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import framework.Food; import framework.Manager; public class Main { public static void main(String[] args) { final Manager manager = new Manager(); final Fish fish = new Fish("さば"); final Fruits fruits = new Fruits("リンゴ"); //登録 manager.register("saba", fish); manager.register("apple", fruits); //生成と使用 final Food food = manager.create("saba"); food.eat(); final Food food2 = manager.create("apple"); food2.eat(); } } |
ここまできて恐縮なんですが、どうやらcloneメソッドは使い勝手が悪く、普通にコピーコンストラクタを定義した方が良いのでは?
と参考書には記載されています:)