Skip to main content
Javaデザインパターン入門
第2回
今日の講義
1. Strategy
2. Facade
アルゴリズムをごっそり切り替える
Strategyパターン
• 目的
▫ Strategyとは「戦略」という意味。アルゴリズム
を実装した部分をごっそり交換出来るようにし、
同じ問題を別の方法で解くのを容易にするため
Strategyサンプル
• じゃんけんを行うプログラム
• 1つ目の戦略:勝ったら次の手も同じ手を出す
(WinningStrategy)
• 2つ目の戦略:1回前の手から次の手を確率的に
計算する(ProbStrategy)
サンプル クラス一覧
クラス名

解説

Hand

じゃんけんの「手」を表すクラス

Strategy

じゃんけんの「戦略」を表すインターフェース

WinningStrategy

勝ったら次も同じ手を出す戦略を表すクラス

ProbStrategy

1回前の手から次の手を確率的に計算する戦略を表すクラ
ス

Player

じゃんけんを行うプレイヤーを表すクラス

Main

動作テスト用のクラス
サンプル クラス図
Hand.java
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 = {
new Hand(HANDVALUE_GUU),
new Hand(HANDVALUE_CHO),
new Hand(HANDVALUE_PAA),
};
private static final String[] name = {
"グー", "チョキ", "パー",
};
private int handvalue;
Hand.java
private Hand(int handvalue) {
this.handvalue = handvalue;
}
public static Hand getHand(int handvalue) {
return hand[handvalue];
}
public boolean isStrongerThan(Hand h) {
return fight(h) == 1;
}
public boolean isWeakerThan(Hand h) {
return fight(h) == -1;
}
Hand.java

}

private int fight(Hand h) {
if (this == h) {
return 0;
} else if ((this.handvalue + 1) % 3 == h.handvalue) {
return 1;
} else {
return -1;
}
}
@Override
public String toString() {
return name[handvalue];
}
Strategy.java
public interface Strategy {
public abstract Hand nextHand();
public abstract void study(boolean win);
}
WinningStrategy.java
import java.util.Random;
public class WinningStrategy implements Strategy {
private Random random;
private boolean won;
private Hand prevHand;
public WinningStrategy(int seed) {
random = new Random(seed);
}
@Override
public Hand nextHand() {
if (!won) {
prevHand = Hand.getHand(random.nextInt(3));
}
return prevHand;
}
@Override
public void study(boolean win) {
won = win;
}
}
ProbStrategy.java
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);
}
ProbStrategy.java
@Override
public Hand nextHand() {
int bet = random.nextInt(getSum(currentHandValue));
int handvalue = 0;
if (bet < history[currentHandValue][0]) {

} else if (bet < history[currentHandValue][0] +
history[currentHandValue][1]) {
handvalue = 1;
} else {
handvalue = 2;
}
prevHandValue = currentHandValue;
currentHandValue = handvalue;
return Hand.getHand(handvalue);
}
ProbStrategy.java
private int getSum(int hv) {
int sum = 0;
for (int i = 0; i < 3; i++) {
sum += history[hv][i];
}
return sum;
}
@Override
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();
}
Player.java
public void win() {
strategy.study(true);
wincount++;
gamecount++;
}
public void lose() {
strategy.study(false);
losecount++;
gamecount++;
}
public void even() {
gamecount++;
}
@Override
public String toString() {
return "[" + name + ":" + gamecount + " games, " + wincount + "win, " +
losecount + " lose]";
}
}
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();
}
}
サンプルプログラム補足
• Strategy(戦略)の役
▫ 戦略を利用するためのインターフェース

• ConcreteStrategy(具体的な戦略)の役
▫ Strategy役のインターフェースを実際に実装する
クラス。具体的な戦略(作戦・方策・方法・アル
ゴリズム)を実際にプログラミングする

• Context(文脈)の役
▫ Strategy役を利用するクラス。ConcreteStrategy役
のインスタンスを持っていて、必要に応じて利用
する
関連しているパターン
• Flyweightパターン
▫ ConcreteStrategy役は、Flyweightパターンを使っ
て複数箇所から共有出来る場合がある

• AbstractFactoryパターン
▫ 具体的な工場・部品・製品をごっそり切り替える
ことが出来る

• Stateパターン
▫ StateパターンもStrategyパターンもともに移譲先
を切り替えるパターン
演習1
• でたらめに次の手を出すRandomStrategyクラス
を作成しなさい
シンプルな窓口
Facadeパターン
• 目的
▫ プログラムはだんだんと巨大化していく傾向があ
る。
▫ 大きなプログラムを使って処理を行うためには、
関係しあっているたくさんのクラスを適切に制御
する必要がある。
▫ 個別に制御するのは大変なので、「窓口」を容易
し、「窓口」に対して要求を出すだけで良いよう
にする
サンプル クラス一覧
パッケージ

クラス名

解説

pagemaker

Singleton

メールアドレスからユーザー名を得るクラス

pagemaker

HtmlWriter

HTMLファイルを作成するクラス

pagemaker

PageMaker

メールアドレスからユーザのWebページを作成す
るクラス

無名

Main

動作テスト用のクラス
サンプル クラス図
Database.java
package facade.pagemaker;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Database {
private Database() {
// new でインスタンス生成させないため
にprivate宣言
}
Database.java
public static Properties getProperties(String dbname) {
String filename = dbname + ".txt";
Properties properties = new Properties();
try {
properties.load(new
FileInputStream(filename));
} catch(IOException e) {
System.out.println("Warning : " +
filename + "is not found." );
}
return properties;
}
}
データファイル(maildata.txt)
•
•
•
•

ykato@ykato.com=Yukiko Kato
hanako@ykato.com=Hanako Sato
tomura@ykato.com=Tomura
mamoru@ykato.com=Mamoru Takahashi
HtmlWriter.java
package pagemaker;
import java.io.IOException;
import java.io.Writer;
public class HtmlWriter {
private Writer writer;
public HtmlWriter(Writer writer) {
this.writer = writer;
}
public void title(String title) throws IOException {
writer.write("<html>");
writer.write("<head>");
writer.write("<title>" + title + "</title>");
writer.write("</head>");
writer.write("<body>n");
writer.write("<h1>" + title + "</h1>n");
}
HtmlWriter.java
public void paragrah(String msg) throws IOException {
writer.write("<p>" + msg + "</p>");
}
public void link(String href, String caption) throws IOException {
paragrah("<a href="" + href + "">" + caption + "</a>");
}
public void mailto(String mailaddr, String username) throws
IOException {
link("mailto:" + mailaddr, username);
}
public void close() throws IOException {
writer.write("</body>");
writer.write("</html>n");
writer.close();
}
}
PageMaker.java
package pagemaker;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PageMaker {

言

private PageMaker() {
// インスタンスは作らないのでprivate宣
}
PageMaker.java
public static void makeWelcomePage(String mailaddr, String filename) {
try {
Properties mailprop = Database.getProperties("maildata");
String username = mailprop.getProperty(mailaddr);
HtmlWriter writer = new HtmlWriter(new
FileWriter(filename));
writer.title("Welcome to " + username + "'s page!");
writer.paragrah(username + "のページへようこそ。");
writer.paragrah("メール待ってますね");
writer.mailto(mailaddr, username);
writer.close();
System.out.println(filename + " is created for " + mailaddr + "
(" + username + ")");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Main.java
import facade.pagemaker.PageMaker;
public class Main {

public static void main(String[] args) {
PageMaker.makeWelcomePage("ykato@ykato.c
om", "welcome.html");
}
}
Facadeパターンの登場人物
• Facade(正面)の役
▫ システムを構成しているその他大勢の役のシンプ
ルな窓口

• システムを構成しているその他大勢の役
▫ それぞれの仕事を行うが、Facade役のことは意識
しない。Facadeから呼び出されて仕事を行うが、
その他大勢からFacade役を呼び出すことはない

• Client(依頼人)の役
▫ Facadeパターンを利用する役
関連しているパターン
• AbstractFactoryパターン
▫ オブジェクト生成という複雑な作業に関する
Facadeパターンとみなすことが出来る
▫ 「オブジェクトを生成するには、このメソッドを
呼べばOK」

• Singletonパターン
▫ Facade役はSingletonパターンとして作られること
がある

• Mediatorパターン
▫ Facadeは一方向で使用するが、Mediatorパターン
は双方向である
参考
• [増補改訂版]Java言語で学ぶデザインパターン
入門
▫ 結城浩著