Mais conteúdo relacionado Semelhante a Javaデザインパターン入門【第2回】 (20) Javaデザインパターン入門【第2回】4. Factory Methodパターン
• 目的
▫ オブジェクトを生成するときのインターフェース
だけを規定して、実際にどのクラスをインスタン
ス化するかはサブクラスが決めるようにする
• 具体的な施策
▫ インスタンス化はすべてサブクラス側で行う
9. Factory.java
package framwork;
public abstract class Factory {
public final Product create(String owner) {
Product product = createProduct(owner);
registerProduct(product);
return product;
}
protected abstract Product createProduct(String owner);
protected abstract void registerProduct(Product product);
}
10. IDCard.java
package idcard;
import framwork.Product;
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 this.owner;
}
}
11. IDCardFactory.java
package idcard;
import java.util.ArrayList;
import java.util.List;
import framwork.Factory;
import framwork.Product;
public class IDCardFactory extends Factory {
private List owners = new ArrayList();
public List getOwners() {
return owners;
}
@Override
protected Product createProduct(String owner) {
return new IDCard(owner);
}
@Override
protected void registerProduct(Product product) {
owners.add(((IDCard)product).getOwner());
}
}
12. Main.java
import framwork.Factory;
import framwork.Product;
import idcard.IDCardFactory;
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();
}
}
14. 関連しているパターン
• Template Methodパターン
▫ Factory Methodパターンは、Template Methodパターンの
典型的な応用。サンプルプログラムのcreateメソッドが
Template Methodになっている
• Singletonパターン
▫ Creater役を務めるクラスは、多くの場合、Singletonパ
ターンとして作ることが出来る。
• Compositeパターン
▫ Product役にCompositeパターンを当てはめることが出来る
場合がある
• Iteratorパターン
▫ IteratorパターンでiteratorメソッドがIteratorのインスタン
スを生成するときにFactory Methodパターンが使われるこ
とがある
20. Singleton.java
public class Singleton {
private static Singleton singleton = new
Singleton();
private Singleton() {
System.out.println("インスタンスを生成
しました");
}
public static Singleton getInstance() {
return singleton;
}
}
21. Main.java
public class Main {
です");
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if (obj1 == obj2) {
System.out.println("obj1とobj2は同じインスタンス
} else {
System.out.println("obj1とobj2は同じインスタンス
ではありません");
}
System.out.println("End.");
}
}
24. Abstract Factoryパターン
• 目的
▫ オブジェクト指向における「抽象的」という言葉
は、「具体的にどのように実装されているかにつ
いては考えず、インターフェース(API)だけに注
目している」状態を指す
▫ 部品の具体的な実装だけには注目せず、インター
フェース(API)に注目し、そのインターフェース
(API)だけを使って、部品を製品にまとめる
32. Page.java
package factory;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
public abstract class Page {
protected String title;
protected String author;
protected ArrayList<Item> content = new ArrayList<Item>();
public Page(String title, String author) {
this.title = title;
this.author = author;
}
public void add(Item item) {
content.add(item);
}
33. Page.java
public void output() {
try {
String filename = title + ".html";
Writer writer = new FileWriter(filename);
writer.write(this.makeHTML());
writer.close();
System.out.println(filename + "を作成し
ました");
} catch (IOException e) {
e.printStackTrace();
}
}
public abstract String makeHTML();
}
34. Factory.java
package factory;
public abstract class Factory {
public static Factory getFactory(String classname) {
Factory factory = null;
try {
factory = (Factory) Class.forName(classname).newInstance();
} catch(ClassNotFoundException e) {
System.out.println("クラス " + classname + " が見つかりません");
} catch (Exception e) {
e.printStackTrace();
}
return factory;
}
public abstract Link createLink(String caption, String url);
public abstract Tray createTray(String caption);
public abstract Page createPage(String title, String author);
}
35. Main.java
package abstractfactory;
import factory.Factory;
import factory.Link;
import factory.Page;
import factory.Tray;
public class Main {
public static void main(String[] args) {
// Linkfactory
Factory factory = Factory.getFactory("listfactory.ListFactory");
Link asahi = factory.createLink("朝日新聞", "http://www.asahi.com/");
Link yomiuri = factory.createLink("読売新聞", "http://www.yomiuri.co.jp/");
Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://yahoo.co.jp/");
Link excite = factory.createLink("Excite", "http://www.excite.com/");
Link google = factory.createLink("Google", "http://www.google.com/");
36. Main.java
Tray traynews = factory.createTray("新聞");
traynews.add(asahi);
traynews.add(yomiuri);
Tray trayyahoo = factory.createTray("Yahoo!");
trayyahoo.add(us_yahoo);
trayyahoo.add(jp_yahoo);
Tray traysearch = factory.createTray("サーチエンジン");
traysearch.add(trayyahoo);
traysearch.add(excite);
traysearch.add(google);
Page page = factory.createPage("LinkPage", "yukiko kato");
page.add(traynews);
page.add(traysearch);
page.output();
}
}
37. ListFactory.java
package listfactory;
import factory.Factory;
import factory.Link;
import factory.Page;
import factory.Tray;
public class ListFactory extends Factory {
@Override
public Link createLink(String caption, String url) {
return new ListLink(caption, url);
}
@Override
public Tray createTray(String caption) {
return new ListTray(caption);
}
@Override
public Page createPage(String title, String author) {
return new ListPage(title, author);
}
}
39. ListTray.java
package listfactory;
import java.util.Iterator;
import factory.Item;
import factory.Tray;
public class ListTray extends Tray {
public ListTray (String caption) {
super(caption);
}
@Override
public String makeHTML() {
StringBuffer sb = new StringBuffer();
sb.append("<li>n");
sb.append(caption + "n");
sb.append("<ul>n");
Iterator<Item> it = tray.iterator();
while(it.hasNext()) {
Item item = (Item) it.next();
sb.append(item.makeHTML());
}
sb.append("</ul>n");
sb.append("</li>n");
return sb.toString();
}
}
40. ListPage.java
package listfactory;
import java.util.Iterator;
import factory.Item;
import factory.Page;
public class ListPage extends Page{
public ListPage(String title, String author) {
super(title, author);
}
public String makeHTML() {
StringBuffer sb = new StringBuffer();
sb.append("<html><head><title>" + title + "</title></head>n");
sb.append("<body>n");
sb.append("<h1>" + title + "</h1>n");
sb.append("<ul>n");
Iterator<Item> iterator = content.iterator();
while (iterator.hasNext()) {
Item item = iterator.next();
sb.append(item.makeHTML());
}
sb.append("</ul>n");
sb.append("<hr><address>" + author + "</address>");
sb.append("</body></html>n");
return sb.toString();
}
}
53. State.java(インターフェース)
public interface State {
public abstract void doClock(Context context,
int hour);
public abstract void doUse(Context context);
public abstract void doAlarm(Context
context);
public abstract void doPhone(Context
context);
}
54. DayState.java
public class DayState implements State {
private static DayState singleton = new DayState();
private DayState() {
}
public static State getInstance() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if (hour < 9 || 17 <= hour) {
context.changeState(NightState.getInstance());
}
}
55. DayState.java
@Override
public void doUse(Context context) {
context.recordLog("金庫使用(昼間)");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("非常ベル(昼間)");
}
@Override
public void doPhone(Context context) {
context.callSecurityCenter("通常の通話(昼間)");
}
@Override
public String toString() {
return "[昼間]";
}
}
56. NightState.java
public class NightState implements State {
private static NightState singleton = new NightState();
private NightState() {
}
public static State getInstance() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if (9 <= hour && hour < 17) {
context.changeState(DayState.getInstance());
}
}
57. NightState.java
@Override
public void doUse(Context context) {
context.callSecurityCenter("非常:夜間の金庫使用!");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("非常ベル(夜間)");
}
@Override
public void doPhone(Context context) {
context.recordLog("夜間の通話録音");
}
@Override
public String toString() {
return "[夜間]";
}
}
58. Context.java(インターフェース)
public interface Context {
public abstract void setClock(int hour);
public abstract void changeState(State state);
public abstract void
callSecurityCenter(String msg);
public abstract void recordLog(String msg);
}
59. SafeFrame.java
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SafeFrame extends Frame implements Context , ActionListener{
// 現在時刻表示
private TextField textClock = new TextField(60);
// 警備センター出力
private TextArea textScreen = new TextArea(10, 60);
// 金庫使用ボタン
private Button buttonUse = new Button("金庫使用");
// 非常ベルボタン
private Button buttonAlarm = new Button("非常ベルボタン");
// 通常通話ボタン
private Button buttonPhone = new Button("通常通話");
// 終了ボタン
private Button buttonExit = new Button("終了");
private State state = DayState.getInstance();
60. SafeFrame.java
public SafeFrame(String title) {
super(title);
setBackground(Color.lightGray);
setLayout(new BorderLayout());
// textClockを配置
add(textClock, BorderLayout.NORTH);
textClock.setEditable(false);
// textScreenを配置
add(textScreen, BorderLayout.CENTER);
textScreen.setEditable(false);
// パネルにボタンを格納
Panel panel = new Panel();
panel.add(buttonUse);
panel.add(buttonAlarm);
panel.add(buttonPhone);
panel.add(buttonExit);
// そのパネルを配置
add(panel, BorderLayout.SOUTH);
// 表示
pack();
setVisible(true);
// リスナーの設定
buttonUse.addActionListener(this);
buttonAlarm.addActionListener(this);
buttonPhone.addActionListener(this);
buttonExit.addActionListener(this);
}
61. SafeFrame.java
// ボタンが押されたらここに来る
public void actionPerformed(ActionEvent e) {
System.out.println(e.toString());
if (e.getSource() == buttonUse) {
// 金庫使用ボタン
state.doUse(this);
} else if (e.getSource() == buttonAlarm) { // 非常ベルボタン
state.doAlarm(this);
} else if (e.getSource() == buttonPhone) { // 通常通話ボタン
state.doPhone(this);
} else if (e.getSource() == buttonExit) { // 終了ボタン
System.exit(0);
} else {
System.out.println("?");
}
}
62. SafeFrame.java
// 時刻の設定
public void setClock(int hour) {
String clockstring = "現在時刻は";
if (hour < 10) {
clockstring += "0" + hour + ":00";
} else {
clockstring += hour + ":00";
}
System.out.println(clockstring);
textClock.setText(clockstring);
state.doClock(this, hour);
}
63. SafeFrame.java
// 状態変化
public void changeState(State state) {
System.out.println(this.state + "から" + state + "へ状態が変化し
ました。");
this.state = state;
}
// 警備センター警備員呼び出し
public void callSecurityCenter(String msg) {
textScreen.append("call! " + msg + "n");
}
// 警備センター記録
public void recordLog(String msg) {
textScreen.append("record ... " + msg + "n");
}
}
64. Main.java
public class Main {
public static void main(String[] args) {
SafeFrame frame = new SafeFrame("State Sample");
while (true) {
for (int hour = 0; hour < 24; hour++) {
frame.setClock(hour); // 時刻の設定
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
}
65. Stateパターンの登場人物
• State(状態)の役
▫ 状態を表す
▫ 状態ごとに異なる振る舞いをするインターフェース
(API)を定める
▫ このインターフェース(API)は、状態に依存した振る
舞いをするメソッドの集まりになる
• ConcreteState(具体的な状態)の役
▫ 具体的な個々の状態を表現する
▫ State役で定められたインターフェースを実装する
• Context(状況、前後関係、文脈)の役
▫ 現在の状態を表すConcreteState役を持つ
▫ Stateパターンの利用者に必要なインターフェース
(API)を定める