Factory Methodパターン
Template Methodパターンではスーパークラス側で処理の骨組みを作り、サブクラス側で具体的な処理の肉付けを行う。
このパターンをインスタンス生成の場面に適用したものがFactory Methodパターン。
Product (製品)の役
このパターンで生成されるインスタンスが持つべきインタフェースを定める抽象クラス。
具体的な内容はConcreteProduct役が定める。
package factoryMethod;
public abstract class Product {
public abstract void use();
}
Creator(作成者)の役
Product役を生成する抽象クラス。
具体的な内容はContreteCreatorが定める。
Creator役は実際に生成するConcreteProduct役については何も知らない。
Creator役が知っているのは、Product役とインスタンス生成のメソッドを呼び出せば、Productが生成されるということだけ。
newによる実際のインスタンス生成をインスタンス生成のためのメソッド呼び出しに代えることで、具体的なクラス名による束縛からスーパークラスを解放していることになる。
package factoryMethod;
public abstract class Factory {
public final Product create(String owner) {
Product p = createProduct(owner);
registerProduct(p);
return p;
}
protected abstract Product createProduct(String owner);
protected abstract void registerProduct(Product product);
}
ConcreteProduct(具体的製品)の役
具体的な製品を定める。
package factoryMethod;
public class IdCard extends Product {
private String owner;
public IdCard(String owner) {
System.out.println(owner + "のカードを作ります");
this.owner = owner;
}
@Override
public void use() {
System.out.println(owner + "のカードを使います");
}
public String getOwner() {
return owner;
}
}
ConcreteCreator(具体的作成者)の役
具体的な製品を作るクラスを定める。
package factoryMethod;
import java.util.ArrayList;
import java.util.List;
public class IdCardFactory extends Factory {
private List<String> owners = new ArrayList<>();
@Override
protected Product createProduct(String owner) {
return new IdCard(owner);
}
@Override
protected void registerProduct(Product product) {
owners.add(((IdCard)product).getOwner());
}
public List<String> getOwners() {
return owners;
}
}
呼び出し元
package factoryMethod;
public class Main {
public static void main(String[] args) {
Factory factory = new IdCardFactory();
Product card1 = factory.create("田中");
Product card2 = factory.create("鈴木");
Product card3 = factory.create("佐藤");
card1.use();
card2.use();
card3.use();
}
}
//実行結果
//田中のカードを作ります
//鈴木のカードを作ります
//佐藤のカードを作ります
//田中のカードを使います
//鈴木のカードを使います
//佐藤のカードを使います
上記IdCardクラスに、通し番号を追加し、IdCardFactoryクラスが通し番号と所有者の対応表を持つよう修正を行った。
package factoryMethod;
public class IdCard extends Product {
private String owner;
private int serial;
public IdCard(String owner, int serial) {
System.out.println(owner + "(" + serial + ")のカードを作ります");
this.owner = owner;
this.serial = serial;
}
@Override
public void use() {
System.out.println(owner + "(" + serial + ")のカードを使います");
}
public String getOwner() {
return owner;
}
public int getSerial() {
return serial;
}
}
package factoryMethod;
import java.util.HashMap;
public class IdCardFactory extends Factory {
private HashMap<Integer, String> database = new HashMap<>();
private int serial = 1;
@Override
protected synchronized Product createProduct(String owner) {
return new IdCard(owner, serial++);
}
@Override
protected void registerProduct(Product product) {
IdCard card = (IdCard)product;
database.put(card.getSerial(), card.getOwner());
}
public HashMap<Integer, String> getDatabase() {
return database;
}
}
package factoryMethod;
public class Main {
public static void main(String[] args) {
Factory factory = new IdCardFactory();
Product card1 = factory.create("田中");
Product card2 = factory.create("鈴木");
Product card3 = factory.create("佐藤");
card1.use();
card2.use();
card3.use();
}
}
// 実行結果
//田中(1)のカードを作ります
//鈴木(2)のカードを作ります
//佐藤(3)のカードを作ります
//田中(1)のカードを使います
//鈴木(2)のカードを使います
//佐藤(3)のカードを使います
Productクラス、Factoryクラス、Mainクラスを変更することなく修正を行うことができた。
こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門