Singlton
特徴
オブジェクト(インスタンス)が1個しか存在しないことを保証するパターン
クラス図
Singlton
−singlton −Singlton( ) +getInstance( ) − : private + : public を表す : static各クラスの説明
Singlton
インスタンスが1つしか存在しないクラス
※ コンストラクタが private であり,Singlton クラス外からコンストラクタを呼び出すことを禁止している.
※ インスタンスを作成する場合(コンストラクタを実行する場合)ではクラスメソッドの getInstance( )を呼ぶ.
※ クラス変数の singlton が private としてあり,これにより唯一のインスタンスを決定している.(自分のイ
ンスタンスを持つ)
適用例
(「Java 言語で学ぶデザインパターン入門」より)(クラス図は上に同じ)
Singlton クラスより2つのインスタンスを作成する.この2つのインスタンスが同一であることを示す.(表示
する)
Singleton.java
1:public class Singleton {
2: private static Singleton singleton = new Singleton( ); // Singlton クラスが呼ばれたときに1回のみ実行 3: private Singleton( ) { // コンストラクタ(private 型)
4: System.out.println("インスタンスを生成しました。"); 5: }
6: public static Singleton getInstance( ) { // インスタンスを作成するためのメソッド
7: return singleton; // (自分の持つインスタンスを返す) 8: }
9:}
Main.java
1:public class Main {
2: public static void main(String[ ] args) { 3: System.out.println("Start.");
4: Singleton obj1 = Singleton.getInstance( ); // Singlton のクラスメソッドの getInstance( )により 5: Singleton obj2 = Singleton.getInstance( ); // インスタンスを作成 6: if (obj1 == obj2) { // もし、インスタンス obj1 と obj2 が同じならば、 7: System.out.println("obj1 と obj2 は同じインスタンスです。"); // このメッセージが表示される 8: } else { 9: System.out.println("obj1 と obj2 は同じインスタンスではありません。"); 10: } 11: System.out.println("End."); 12: } 13:} 実行結果 ¥>java Main Start. インスタンスを生成しました。 obj1 と obj2 は同じインスタンスです。 End.
State
特徴
ときどきの状態に合わせて動作の内容を変更するパターン
各状態を異なるクラスで表現し,クラスを切り替えることにより状態を変化させるパターン
クラス図
Context State requestX( ) requestY( ) requestZ( ) State methodA( ) methodB( ) methodC( ) methodD( ) ConcreateState1 methodA( ) methodB( ) methodC( ) methodD( ) ConcreateState2 methodA( ) methodB( ) methodC( ) methodD( ) 斜字体は 抽象(abstract)クラス, メソッドなどを表す各クラスの説明
Context
状態に対して動作を呼ぶクラス
State
状態を表すクラスであり,状態における動作のインターフェースの役割を行う
(各状態の動作をカプセル化する)
ConcreateState
具体的な状態を表すクラス
※ConcreateState に動作を記述し,Context で保持することにより,(動作あるいはプログラムの)管理,
保守が簡単になる.
適用例
(「Java 言語で学ぶデザインパターン入門」より)金庫警備システムを考える.このシステムでは,昼間と夜間の2つの管理する状態が存在する.
金庫警備システムでは以下の機能を有する.
条件
・金庫には警備センターと接続されている
・金には非常ベルが接続されている
・金庫には時計がついており、現在の時計を監視している
・昼間は 9:00~16:59,夜間は 17:00~8:59
金庫の利用について
・金庫は昼のみ利用できる
・昼間に利用されると、警備センターの記録が残る
・夜間に利用されると、警備センターに非常事態の
通報が行く
非常ベルについて
・非常ベルはいつでも利用できる
・非常ベルを使用すると、警備センターに非常ベル
の通報が行く
SafeFrame SafeFrameSafeFrame SafeFrame −state setClock( ) changeState( ) callSecurityCenter( ) recoerdLog( ) <<interface>> State State State State doClock( ) doUse( ) doAlarm( ) NightState NightState NightState NightState −singlton −NightState( ) getInstance( ) doClock( ) doUse( ) doAlarm( ) 具体 的にプロ グ ラ ム(処理)を記述 DayState DayState DayState DayState −singlton −DayState( ) getInstance( ) doClock( ) doUse( ) doAlarm( ) <<interface>> Context ContextContext Context setClock( ) changeState( ) callSecurityCenter( ) recoerdLog( ) 抽象クラス 抽象クラス 抽象クラス 抽象クラス メソッドは実装 していない
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); // 非常ベル }
DayState.java
(昼間の処理用クラス,(昼間の処理用クラス,Singlton パターンを利用している)(昼間の処理用クラス,(昼間の処理用クラス, パターンを利用している)パターンを利用している)パターンを利用している)public class DayState implements State {
private static DayState singleton = new DayState( );
private DayState() { // コンストラクタは private }
public static State getInstance() { // 唯一のインスタンスを得る return singleton;
}
public void doClock(Context context, int hour) { // 時刻設定 ④時間を見て,もし夜の時間ならば if (hour < 9 || 17 <= hour) { // Frame の状態を夜間に変更 context.changeState(NightState.getInstance());
} }
public void doUse(Context context) { // 金庫使用 context.recordLog("金庫使用(昼間)");
}
public void doAlarm(Context context) { // 非常ベル context.callSecurityCenter("非常ベル(昼間)");
}
public String toString() { // 文字列表現 return "[昼間]";
} }
NightState.java
(夜間の処理用クラス,(夜間の処理用クラス,Singlton パターンを利用している)(夜間の処理用クラス,(夜間の処理用クラス, パターンを利用している)パターンを利用している)パターンを利用している)public class NightState implements State {
private static NightState singleton = new NightState();
}
public static State getInstance() { // 唯一のインスタンスを得る return singleton;
}
public void doClock(Context context, int hour) { // 時刻設定 ④時間を見て,もし昼の時間ならば if (9 <= hour && hour < 17) { // Frame の状態を昼間に変更 context.changeState(DayState.getInstance());
} }
public void doUse(Context context) { // 金庫使用 context.callSecurityCenter("非常:夜間の金庫使用!"); }
public void doAlarm(Context context) { // 非常ベル context.callSecurityCenter("非常ベル(夜間)");
}
public String toString() { // 文字列表現 return "[夜間]";
} }
Main.java
public class Main extends Thread {
public static void main(String[] args) {
SafeFrame frame = new SafeFrame("State Sample"); // GUI の表示
while (true) { // 無限ルーチンで時計をまわしている for (int hour = 0; hour < 24; hour++) {
frame.setClock(hour); // 時刻の設定 ①GUI(Frame)に時間を渡している try { Thread.sleep(1000); } catch (InterruptedException e) { } } } } }
Context.java
(GUI 部のためのインターフェース部のためのインターフェース部のためのインターフェース部のためのインターフェース)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); // 警備センター記録 }
SafeFrame.java (GUI とイベント処理のためのプログラム
とイベント処理のためのプログラム
とイベント処理のためのプログラム
とイベント処理のためのプログラム)
import java.awt.Frame; import java.awt.Label; import java.awt.Color; import java.awt.Button; import java.awt.TextField; import java.awt.TextArea; import java.awt.Panel; import java.awt.BorderLayout; import java.awt.event.ActionListener; import java.awt.event.ActionEvent;public class SafeFrame extends Frame implements ActionListener, Context { 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 buttonExit = new Button("終了"); // 終了ボタン
private State state = DayState.getInstance(); // 現在の状態 // コンストラクタ
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(buttonExit); // そのパネルを配置 add(panel, BorderLayout.SOUTH); // 表示 pack(); show(); // リスナーの設定 buttonUse.addActionListener(this); buttonAlarm.addActionListener(this); buttonExit.addActionListener(this); } // ボタンが押されたらここに来る
public void actionPerformed(ActionEvent e) { System.out.println("" + e);
if (e.getSource() == buttonUse) { // 金庫使用ボタン state.doUse(this);
} else if (e.getSource() == buttonAlarm) { // 非常ベルボタン state.doAlarm(this);
} else if (e.getSource() == buttonExit) { // 終了ボタン System.exit(0); } else { System.out.println("?"); } } // 時刻の設定
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); // ③現状態の doClock()へ時間が渡される(それぞれの } // 状態のクラスへ渡される.引数にこの Frame // 状態変化
public void changeState(State state) {
System.out.println(this.state + "から" + state + "へ状態が変化しました。"); this.state = state;
}
// 警備センター呼び出し
textScreen.append("call! " + msg + "¥n"); }
// 警備センター記録
public void recordLog(String msg) {
textScreen.append("record ... " + msg + "¥n"); }
}
Strategy
特徴
共通の目的に対して,具体的な戦略を複数用意しておき,その場の状況によって戦略を選ぶ場合のパ
ターン
具体的な個別の戦略を異なるクラスを表現するため,共通化されたインターフェースから実装する.
クラス図
Context Strategy contextMethod Strategy strategyMethod ConcreteStrategy1 strategyMethod ConcreteStrategy2 strategyMethod各クラスの説明
Context
戦略を利用するクラス
Strategy
戦略を表すクラスであり,具体的な戦略のインターフェースの役割を行う
(ここでの戦略は広い意味のものであり,目的を指す.そしてこのインターフェー
スを通して各戦略をカプセル化する)
ConcreteStrategy
具体的な戦略を実装するクラス
※ConcreteStrategy に具体的な戦略を記述し,Context で保持することにより,その場の状況によって
戦略を選び実行する.
適用例1.
(「UMLPress Vol.1」より)A さんは今夜,彼女とデートするためも持ち合わせのお金がありません.そこで,お金を調達する方法
(戦略)として「銀行の預金からお金をおろす」,「友達からお金を借りる」「消費者金融の ATM からキャッシ
ングする」の3方法を考えている.
お金が必用な状況 お金を手に入れる 戦略 お金を手に入れる 銀行からおろす 友達に借りる 具体 的にプロ グ ラ ム(処理)を記述 消費者金融に借りる適用例2
(「Java 言語で学ぶデザインパターン入門」より)コンピュータ上でじゃんけんを行うものとし,戦略として「勝ったら次も同じものを出す」,「1回前の手から
確立より決める」の2種類を設定する.
下記のプログラムでは2者間のじゃんけんの結果を表示する.
Player Strategy nextHand win lose even <<interface>> Strategy nextHand study WinningStrategy nextHand study ProbStrategy nextHand study じゃんけんの「戦略」を表す インターフェース 抽象クラスのため,この中のメソ ッドでは実装しない(宣言のみ) 勝ったら次ぎも同じ手を出 す「戦略」を表すクラス インターフェースで宣言した メソッドを実装 1回前の手から次の手を確率 的に計算する「戦略」を表すク ラス インターフェースで宣言し たメソッドを実装 じゃんけんを行うプレイヤー を表す
Hand クラス
じゃんけんの「手」を表すクラス.クラス内部でグー,チョキ,パーを 0,1,2 で表現する
メソッド:
Hand getHand( ) (クラスメソッド): インスタンスを得る
bool isStringerThan( Hand hand1) : hand1 に対して強ければ true, 弱ければ false を返す
bool IsWeakerThan( Hand hand1) : hand1 に対して弱ければ true, 強ければ false を返す
Hand.java (Strategy
パターンと関係ないが,
パターンと関係ないが,
パターンと関係ないが,
パターンと関係ないが,
Strategy, WinningStrategy, ProbStrategy
で利用される
で利用される
で利用される
で利用される
)
public class Hand {public static final int HANDVALUE_GUU = 0; // グーを表す値 public static final int HANDVALUE_CHO = 1; // チョキを表す値 public static final int HANDVALUE_PAA = 2; // パーを表す値
public static final Hand[] hand = { // じゃんけんの手を表す 3 つのインスタンス new Hand(HANDVALUE_GUU),
new Hand(HANDVALUE_CHO), new Hand(HANDVALUE_PAA), };
private static final String[] name = { // じゃんけんの手の文字列表現 "グー", "チョキ", "パー",
};
private int handvalue; // じゃんけんの手の値 private Hand(int handvalue) {
this.handvalue = handvalue; }
public static Hand getHand(int handvalue) { // 値からインスタンスを得る return hand[handvalue];
}
public boolean isStrongerThan(Hand h) { // this が h より強いとき true return fight(h) == 1;
}
public boolean isWeakerThan(Hand h) { // this が h より弱いとき true return fight(h) == -1;
}
private int fight(Hand h) { // 引き分けは 0, this の勝ちなら 1, h の勝ちなら-1 if (this == h) {
} else if ((this.handvalue + 1) % 3 == h.handvalue) { return 1; } else { return -1; } }
public String toString() { // 文字列表現へ変換 return name[handvalue];
} }
Strategy.java (Strategy
のため
のため
のため
のためのインターフェース
のインターフェース
のインターフェース
のインターフェース
(メソッド
(メソッド
(メソッド
(メソッドの宣言のみ)
の宣言のみ)
の宣言のみ)
の宣言のみ)
)
public interface Strategy {public abstract Hand nextHand( ); public abstract void study(boolean win); }
WinningStrategy.java (
「勝ったら次ぎも同じものをだす」
「勝ったら次ぎも同じものをだす」
「勝ったら次ぎも同じものをだす」
「勝ったら次ぎも同じものをだす」
Strategy
(メソッドの実装)
(メソッドの実装)
(メソッドの実装)
(メソッドの実装)
)
←1つめの戦略
←1つめの戦略
←1つめの戦略
←1つめの戦略
import java.util.Random;public class WinningStrategy implements Strategy { private Random random;
private boolean won = false; private Hand prevHand;
public WinningStrategy(int seed) { random = new Random(seed); }
public Hand nextHand() { if (!won) {
prevHand = Hand.getHand(random.nextInt(3)); }
return prevHand; }
public void study(boolean win) { won = win;
} }
ProbStrategy .java (
「確率から次ぎも同じものをだす」
「確率から次ぎも同じものをだす」
「確率から次ぎも同じものをだす」
「確率から次ぎも同じものをだす」
Strategy
(メソッドの実装)
(メソッドの実装)
(メソッドの実装)
(メソッドの実装)
)
←2つめの戦略
←2つめの戦略
←2つめの戦略
←2つめの戦略
import java.util.Random;public class ProbStrategy implements Strategy { private Random random;
private int prevHandValue = 0; private int currentHandValue = 0; private int[][] history = {
{ 1, 1, 1, }, { 1, 1, 1, }, { 1, 1, 1, }, };
public ProbStrategy(int seed) { random = new Random(seed); }
public Hand nextHand() {
int bet = random.nextInt(getSum(currentHandValue)); int handvalue = 0;
if (bet < history[currentHandValue][0]) { handvalue = 0;
} else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) { handvalue = 1; } else { handvalue = 2; } prevHandValue = currentHandValue; currentHandValue = handvalue; return Hand.getHand(handvalue);
ここではメソッドを宣言
し,ここの戦略クラスで
実装する
ここでメソッドを実装す
る
ここでメソッドを実装す
る
コンストラクタ
(初めは乱数で出す
ものを設定)
コンストラクタ
(初めは乱数で出す
ものを設定)
確率を計算するためのデータ
を格納する配列
自分が連続して出したものに
対する勝ち数を格納
要素(0,0)→ グー・グー
}
private int getSum(int hv) { int sum = 0;
for (int i = 0; i < 3; i++) { sum += history[hv][i]; }
return sum; }
public void study(boolean win) { if (win) { history[prevHandValue][currentHandValue]++; } else { history[prevHandValue][(currentHandValue + 1) % 3]++; history[prevHandValue][(currentHandValue + 2) % 3]++; } } }
Player.java (
プレイヤーを表すクラス
プレイヤーを表すクラス )
プレイヤーを表すクラス
プレイヤーを表すクラス
public class Player {private String name; private Strategy strategy; private int wincount; private int losecount; private int gamecount;
public Player(String name, Strategy strategy) { // 名前と戦略を授けられる this.name = name;
this.strategy = strategy; }
public Hand nextHand() { // 戦略におうかがいを立てる return strategy.nextHand();
}
public void win() { // 勝った strategy.study(true);
wincount++; gamecount++; }
public void lose() { // 負けた strategy.study(false);
losecount++; gamecount++; }
public void even() { // 引き分け gamecount++;
}
public String toString() {
return "[" + name + ":" + gamecount + " games, " + wincount + " win, " + losecount + " lose" + "]"; }
}
Main.java (
プログラム実行のためのクラス
プログラム実行のためのクラス
プログラム実行のためのクラス
プログラム実行のためのクラス
)
public class Main {public static void main(String[] args) { if (args.length != 2) {
System.out.println("Usage: java Main randomseed1 randomseed2"); System.out.println("Example: java Main 314 15");
System.exit(0); }
int seed1 = Integer.parseInt(args[0]); int seed2 = Integer.parseInt(args[1]);
Player player1 = new Player("Taro", new WinningStrategy(seed1)); Player player2 = new Player("Hana", new ProbStrategy(seed2)); for (int i = 0; i < 10000; i++) {
Hand nextHand1 = player1.nextHand(); Hand nextHand2 = player2.nextHand();
ここでメソッドを実装す
る
コンストラクタ (Main クラスより引数を 通してプレイヤー名と戦 略が渡される) コンストラクタで設定され た戦略に 処理 内容 を 尋 ねる 2人のプレイヤー を設定 じゃんけんを 10000 回行う 乱 数 の 発 生 の 種 をコン ソー ルか ら の引数で与えるif (nextHand1.isStrongerThan(nextHand2)) { System.out.println("Winner:" + player1); player1.win(); player2.lose(); } else if (nextHand2.isStrongerThan(nextHand1)) { System.out.println("Winner:" + player2); player1.lose(); player2.win(); } else { System.out.println("Even..."); player1.even(); player2.even(); } } System.out.println("Total result:"); System.out.println("" + player1); System.out.println("" + player2); } }
実行結果
勝ち・負けの判定 と表示 ¥>java Main 50 33 ・・・… Even...Winner:[Taro:511 games, 164 win, 178 lose] Winner:[Hana:512 games, 178 win, 165 lose] Even...
Winner:[Taro:514 games, 165 win, 179 lose] Even...
Winner:[Taro:516 games, 166 win, 179 lose] ・・・…
Template Method
特徴
スーパークラスで処理の枠組みを定め,サブクラスでその具体的内容を定めるパターン.
アルゴリズムの不変な部分をスーパークラスで実装,変化しうる部分をサブクラスで実装するパターン.
(見方を変えると,サブクラスの共通部分を抜き出してスーパークラスとする.共通でない部分はサブクラス
に設定しておき,必要に応じてサブクラスの入れ替えて対応する.)
クラス図
AbstractClass method1( ) method2( ) method3( ) templateMethod( ) ConcreateClass method1( ) method2( ) method3( ) 斜字体は‘抽象(abstract)’(実体 が無い,実装されていない)であ ることを表す. これらのメソッドから 構成 される 一つの まとまった処理 (テンプレート)各クラスの説明
AbstractClass
(抽象クラス)
共通の作業を表現するクラス(処理の枠組みを定める)
テンプレートメソッドを実装(ConcreateClass で実装する必要のある抽象メソッ
ドを定義する)
個々の処理は抽象クラスとする
ConcreateClass
(具象クラス)
個々の処理を実現(実装)するクラス
(具体的なメソッドを実装)
適用例
(「Java 言語で学ぶデザインパターン入門」より)文字列や文字を 3 回繰り返して画面に表示する場合を考える.
ここで,文字を表示する場合の処理と文字列を表示する場合の処理を別々の具象クラス(それぞれ
CharDisplay, StringDisplay ク ラ ス ) で 表 現 し , 共 通 の 処 理 お よ び 処 理 の 枠 組 み は ス ー パ ー ク ラ ス
(AbstractDisplay クラス)に記述する.処理の枠組みは「open → print を三回 → close 」で行い,各処
理は(スーパークラス内では)抽象メソッドとする(実装しない).
これらのメソッドは各サブクラスで実装する.
クラス名
特徴
AbstractDisplay
メソッド display のみ実装されている抽象クラス(display は処理の枠組みに相当
する.共通の処理の流れ)
CharDisplay
‘文字’表示用メソッド open, print, close を実装しているクラス
StringDisplay
‘文字列’表示用メソッド open, print ,close を実装しているクラス
AbstaractDisplay open( ) print( ) close( ) display( ) CharDisplay open( ) print( ) close( ) StringDisplay open( ) print( ) close( ) printLine( ) テンプレートの メソッド AbstractDisplay AbstractDisplay AbstractDisplay AbstractDisplay.java.java.java.java
public abstract class AbstractDisplay { // 抽象クラス AbstractDisplay
public abstract void open(); // サブクラスに実装をまかせる抽象メソッド open public abstract void print(); // サブクラスに実装をまかせる抽象メソッド print public abstract void close(); // サブクラスに実装をまかせる抽象メソッド close public final void display() { // この抽象クラスで実装しているメソッド display open(); // 初めに open
for (int i = 0; i < 3; i++) { // 3 回 print を繰り返す print( ); } close( ); // 最後に close } } StringDisplay StringDisplay StringDisplay StringDisplay.java.java.java.java
public class StringDisplay extends AbstractDisplay { // StringDisplay も、AbstractDisplay のサブクラス private String string; // 表示するべき文字列
private int width; // バイト単位で計算した文字列の「幅」 public StringDisplay(String string) { // コンストラクタで渡された文字列 string を、 this.string = string; // フィールドに記憶 this.width = string.getBytes().length; // それからバイト単位の幅もフィールドに
} // 記憶しておき、後で使う public void open() { // オーバーライドして定義する open メソッド
printLine(); // このクラスのメソッド printLine で線を引いている }
public void print() { // print メソッドは、
System.out.println("|" + string + "|"); // フィールドに記憶しておいた文字列の前後に"|"を // つけて表示 }
public void close() { // close メソッドは、
printLine(); // open と同じく printLine メソッドで線を引く }
private void printLine() { // open と close から呼ばれる printLine メソッド // private なので、このクラスの中だけで使われる System.out.print("+"); // 枠の角を表現する"+"マークを表示
for (int i = 0; i < width; i++) { // width 個の"-"を表示して、枠線として用いる System.out.print("-"); } System.out.println("+"); // 枠の角を表現する"+"マークを表示 } } CharDisplay CharDisplay CharDisplay CharDisplay.java.java.java.java
public class CharDisplay extends AbstractDisplay { // CharDisplay は、AbstractDisplay のサブクラス。 private char ch; // 表示すべき文字。 このメソッドが 一 連 の 処 理 の流れ 個々のメソッドは抽 象メソッドにし各サ ブクラスで実装
public CharDisplay(char ch) { // コンストラクタで渡された文字 ch を、 this.ch = ch; // フィールドに記憶しておく。
}
public void open() { // スーパークラスでは抽象メソッド
// ここでオーバーライドして実装する System.out.print("<<"); // 開始文字列として"<<"を表示する
}
public void print() { // print メソッドも、ここで実装する
// これが display から繰り返して呼び出される System.out.print(ch); // フィールドに記憶しておいた文字を 1 個表示する。 }
public void close() { // close メソッドも、ここで実装。 System.out.println(">>"); // 終了文字列">>"を表示。 } } Main.java Main.java Main.java Main.java
Public class Main {
public static void main(String[ ] args) {
// 'H'を持った CharDisplay のインスタンスを 1 個作る AbstractDisplay d1 = new CharDisplay('H');
// "Hello, world."を持った StringDisplay のインスタンスを 1 個作る AbstractDisplay d2 = new StringDisplay("Hello, world.");
// "こんにちは。"を持った StringDisplay のインスタンスを 1 個作る AbstractDisplay d3 = new StringDisplay("こんにちは。");
// d1,d2,d3 とも、すべて同じ AbstractDisplay のサブクラスのインスタンスだから、継承した display // メソッドを呼び出すことができる. // 実際の動作は個々のクラス CharDisplay や StringDisplay で定まる d1.display( ); d2.display( ); d3.display( ); }
<注意>
Template Method と Strategy パターンの違い
Template Method パターンは スーパークラスでプログラムの振る舞い(複数メソッドによる処理の流れ, あるいはアルゴリズム)を決めているが,Strategy パターンではスーパークラスではプログラムの振る舞いは 決めておらず,サブクラスでプログラムの振る舞い(アルゴリズム)などを決めている.“処理の流れ”が決まって いれば Template Method を“処理の流れ”ごと交換したければ Strategy の適用となる.