Prototype パターン (原型となるオブジェクトを元に複製する)

[Prototype] という英単語は, [原型], [模範] を意味する.

java では, 複製を作る操作を [Object] クラスが提供する [clone] メソッドを利用して行う. 通常は, [クラス] から [オブジェクト] を作成とう手順 (new を用いて) となるが, このパターンにおいては:

[オブジェクト] から [オブジェクト] (複製) を作成する.

役割

  1. Client (利用者):
[ConcretePrototype] が実装しているオブジェクト複製メソッドを利用して, 新しいオブジェクトを返す.
  1. Prototype (原型):
オブジェクト複製メソッドのインタフェースを定義する. 上記メソッドを [ConcretePrototype] で実装する際に [clone()] メソッドを使用する場合は, [Prototype] に [Cloneable] インタフェースを実装させる.
  1. ConcretePrototype (具体的な原型):
自身のオブジェクトを複製するメソッドを実装する.
  1. PrototypeUser (使用者):
[Prototype] パターンを適用したクラスを利用し処理する.

クラス図

Prototype パターンのクラス図

_images/designpattern-prototype013.gif

ソースコード

  1. Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import java.util.Map;
import java.util.HashMap;

public class Client{
    private Map<String, Prototype> hashmap = new HashMap<String, Prototype>();

    public void regist(String key, Prototype prototype){
	hashmap.put(key, prototype);
    }

    public Prototype create(String key){
	Prototype prototype = hashmap.get(key);
	return prototype.createClone();
    }
}
  1. Prototype.java
1
2
3
4
5
6
7
8
/*
  clone メソッドを使用したい場合, そのスーパークラス•インタフェースのどこで
  Cloneable インタフェースを実装していないといけない.
  Cloneable インタフェースには抽象メソッドが一つも定義されていない. 単にそのクラスが clone できるかどうかのマーク付けをしているだけ.
*/
public abstract class Prototype implements Cloneable{
    public abstract Prototype createClone();
}
  1. ConcretePrototype.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class ConcretePrototype extends Prototype{
    private int id;
    public ConcretePrototype(int id){
	this.id = id;
    }

    public Prototype createClone(){
	ConcretePrototype concretePrototype = null;
	try{
	    concretePrototype = (ConcretePrototype)this.clone();
	}catch(CloneNotSupportedException e){
	    e.printStackTrace();
	}
	return concretePrototype;
    }
    public int getId(){
	return id;
    }
}
  1. PrototypeUser.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class PrototypeUser{
    public static void main(String[] args){
	Client client = new Client();
	ConcretePrototype cp1 = new ConcretePrototype(0);
	ConcretePrototype cp2 = new ConcretePrototype(1);
	ConcretePrototype cp3 = new ConcretePrototype(2);

	client.regist("0", cp1);
	client.regist("1", cp2);
	client.regist("2", cp3);

	Prototype prototype1 = client.create("0");
	Prototype prototype2 = client.create("1");
	Prototype prototype3 = client.create("2");

	System.out.println(((ConcretePrototype)prototype1).getId());
	System.out.println(((ConcretePrototype)prototype2).getId());
	System.out.println(((ConcretePrototype)prototype3).getId());
    }
}

上記のプログラムの実行結果:

[wtopia Prototype]$ java PrototypeUser
0
1
2

オブジェクトの生成方法としては以下の様々な方法がある.

  1. [new] 演算子を用いて, オブジェクトを生成する方法.

一番ポピュラーな生成方法:

String str = new String();
  1. [clone] メソッドを用いて, オブジェクトを生成 (コピー) する方法.

java.lang.Object オブジェクトが定義している clone メソッドを使用して自身のコピーを生成する.

注意:

clone メソッドを使用したい場合, Cloneable インタフェースを実装しておく必要がある. コンストラクタは呼ばれない.

例としては:

class A implements Cloneable{
  public Object copy(){
    A a = null;
    try{
      a = (A)clone();
    }catch(CloneNotSupportedException e){
      e.printStackTrace();
    }
    return a;
  }
}
  1. [newInstance] メソッドを用いてオブジェクトを生成する方法.

java.lang.Class オブジェクトが定義している newInstance メソッドを使用して, 生成する.

注意:

[InstantiationException], [IllegalAccessException] を例外として投げるので, 例外処理をしておく必要がある.
引数なしコンストラクタ (デフォルト) が呼ばれる.

完全修飾クラス名を元にオブジェクトを生成する:

A a = (A)Class.forName("A").newInstance();

既に生成しているオブジェクトを元にオブジェクトを生成する:

A a = new A();
A b = a.getClass().newInstance();