Design Pattern | Prototype Pattern(プロトタイプパターン)
Prototypeパターンとは?
- Prototypeという英単語は、原型や模範という意味である。
- Prototypeパターンは、
new Xxx()でクラスからインスタンスを生成するのではなく、インスタンスから別のインスタンスを生成する方式である。つまり、コピーしてインスタンスを作る。 - 複製を作る作業を
cloneと言う。 - GoFデザインパターンでは、生成に関するデザインパターンに分類される。
Prototypeパターンのサンプルプログラム
入力した文字列に下線を引いたり、囲んだりするサンプルプログラムである。
Class Diagram

1. Productインターフェース
複製メソッドを定義するインターフェースである。JavaのCloneableインターフェースを継承する。
Product.java
package com.devkuma.designpattern.creational.prototype.framework;
import java.lang.Cloneable;
public interface Product extends Cloneable {
void use(String s);
Product createClone();
}
2. Managerクラス
Productの生成指示や管理を行うクラスである。
Manager.java
package com.devkuma.designpattern.creational.prototype.framework;
import java.util.HashMap;
public class Manager {
private HashMap showcase = new HashMap();
public void register(String name, Product prototype) {
showcase.put(name, prototype);
}
public Product create(String prototypeName) {
Product p = (Product) showcase.get(prototypeName);
return p.createClone();
}
}
3. UnderlinePenクラス
Productインターフェースを実装するクラスである。このクラスは「文字に下線を引く」クラスになる。
UnderlinePen.java
package com.devkuma.designpattern.creational.prototype.product;
import com.devkuma.designpattern.creational.prototype.framework.Product;
public class UnderlinePen implements Product {
private char underlineChar;
public UnderlinePen(char underlineChar) {
this.underlineChar = underlineChar;
}
public void use(String s) {
int length = s.getBytes().length;
System.out.println(s);
for (int i = 0; i < length; i++) {
System.out.print(underlineChar);
}
System.out.println();
}
public Product createClone() {
Product p = null;
try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
// オブジェクトのクラスがCloneableインターフェースを実装していない場合にthrowされる例外。
e.printStackTrace();
}
return p;
}
}
4. MessageBoxクラス
Productインターフェースを実装するクラスである。このクラスは「文字を囲む」クラスになる。
MessageBox.java
package com.devkuma.designpattern.creational.prototype.product;
import com.devkuma.designpattern.creational.prototype.framework.Product;
public class MessageBox implements Product {
private char decoChar;
public MessageBox(char decoChar) {
this.decoChar = decoChar;
}
public void use(String s) {
int length = s.getBytes().length;
for (int i = 0; i < length + 2; i++) {
System.out.print(decoChar);
}
System.out.println();
System.out.println(decoChar + s + decoChar);
for (int i = 0; i < length + 2; i++) {
System.out.print(decoChar);
}
System.out.println();
}
public Product createClone() {
Product p = null;
try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
// オブジェクトのクラスがCloneableインターフェースを実装していない場合にthrowされる例外。
e.printStackTrace();
}
return p;
}
}
5. Mainクラス
メイン処理を実行するクラスである。
Main.java
package com.devkuma.designpattern.creational.prototype;
import com.devkuma.designpattern.creational.prototype.framework.Manager;
import com.devkuma.designpattern.creational.prototype.framework.Product;
import com.devkuma.designpattern.creational.prototype.product.MessageBox;
import com.devkuma.designpattern.creational.prototype.product.UnderlinePen;
public class Main {
public static void main(String[] args) {
Manager manager = new Manager();
UnderlinePen upen = new UnderlinePen('~');
MessageBox mbox = new MessageBox('*');
MessageBox pbox = new MessageBox('+');
manager.register("strong message", upen);
manager.register("warning box", mbox);
manager.register("slash box", pbox);
Product p1 = manager.create("strong message");
p1.use("Hello world");
System.out.println();
Product p2 = manager.create("warning box");
p2.use("Hello world");
System.out.println();
Product p3 = manager.create("slash box");
p3.use("Hello world");
}
}
6. 実行結果
Hello world
~~~~~~~~~~~
*************
*Hello world*
*************
+++++++++++++
+Hello world+
+++++++++++++
Prototypeパターンのメリット
サンプルプログラムでは比較的単純な場合だったが、インスタンスを生成するうえで複雑な処理が必要だったり、時間がかかる処理が必要だったりすることもある。インスタンスを生成するたびにnew Xxx()を使うのは非常に非効率である。
Prototypeを作ってコピーすれば、簡単にインスタンスを生成できる。