public class BookShelf implements Aggregate {
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public Book getBookAt(int index) {
return books[index];
}
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
public int getLength() {
return last;
}
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
public interface Aggregate {
public abstract Iterator iterator();
}
Iteratorの実装
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
public boolean hasNext() {
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
使用方法
import java.util.*;
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long-Legs"));
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}
}
}
2. Adapter
すでに提供されているものがそのまま使えず、wrappterして必要な形に変換して利用
以下の2種類
継承
委譲
継承
元々定義されている実装
public class Banner {
private String string;
public Banner(String string) {
this.string = string;
}
public void showWithParen() {
System.out.println("(" + string + ")");
}
public void showWithAster() {
System.out.println("*" + string + "*");
}
}
使用したいインターフェイス
public interface Print {
public abstract void printWeak();
public abstract void printStrong();
}
ここで以下のような継承したクラスを実装
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
public void printWeak() {
showWithParen();
}
public void printStrong() {
showWithAster();
}
}
public class PrintBanner extends Print {
private Banner banner;
public PrintBanner(String string) {
this.banner = new Banner(string);
}
public void printWeak() {
banner.showWithParen();
}
public void printStrong() {
banner.showWithAster();
}
}
3. Template Method
スーパークラスで処理の枠組みを定め、サブクラスでその具体的な内容を定義
複数のクラス間でロジックの抽象化
サブクラスをスーパークラスと同一視可能
スーパークラス型の変数に、サブクラスのインスタンスのどれを代入しても正しく動作するようにする
The Liskov Substition Principle(LSP)
抽象化クラス
public abstract class AbstractDisplay {
public abstract void open();
public abstract void print();
public abstract void close();
public final void display() {
open();
for (int i = 0; i < 5; i++) {
print();
}
close();
}
}
具象クラス1
public class CharDisplay extends AbstractDisplay {
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
public void open() {
System.out.print("<<");
}
public void print() {
System.out.print(ch);
}
public void close() {
System.out.println(">>");
}
}
具象クラス2
public class StringDisplay extends AbstractDisplay {
private String string;
private int width;
public StringDisplay(String string) {
this.string = string;
this.width = string.getBytes().length;
}
public void open() {
printLine();
}
public void print() {
System.out.println("|" + string + "|");
}
public void close() {
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}
使用方法
public class Main {
public static void main(String[] args) {
AbstractDisplay d1 = new CharDisplay('H');
AbstractDisplay d2 = new StringDisplay("Hello, world.");
AbstractDisplay d3 = new StringDisplay("こんにちは。");
d1.display();
d2.display();
d3.display();
}
}
4. Factory Method
インスタンスを生成する工場をTemplate Methodパターンで構成
インスタンスの作り方をスーパークラスの側で定める
抽象化した工場
package framework;
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);
}
抽象化した製造物
package framework;
public abstract class Product {
public abstract void use();
}
具象化した工場
package idcard;
import framework.*;
import java.util.*;
public class IDCardFactory extends Factory {
private List owners = new ArrayList();
protected Product createProduct(String owner) {
return new IDCard(owner);
}
protected void registerProduct(Product product) {
owners.add(((IDCard)product).getOwner());
}
public List getOwners() {
return owners;
}
}
具象化した製造物
package idcard;
import framework.*;
public class IDCard extends Product {
private String owner;
IDCard(String owner) {
System.out.println(owner + "のカードを作ります。");
this.owner = owner;
}
public void use() {
System.out.println(owner + "のカードを使います。");
}
public String getOwner() {
return owner;
}
}
使用方法
import framework.*;
import idcard.*;
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();
}
}
public abstract class Builder {
public abstract void makeTitle(String title);
public abstract void makeString(String str);
public abstract void makeItems(String[] items);
public abstract void close();
}
具象クラスの例
import java.io.*;
public class HTMLBuilder extends Builder {
private String filename;
private PrintWriter writer;
public void makeTitle(String title) {
filename = title + ".html";
try {
writer = new PrintWriter(new FileWriter(filename));
} catch (IOException e) {
e.printStackTrace();
}
writer.println("<html><head><title>" + title + "</title></head><body>");
writer.println("<h1>" + title + "</h1>");
}
public void makeString(String str) {
writer.println("<p>" + str + "</p>");
}
public void makeItems(String[] items) {
writer.println("<ul>");
for (int i = 0; i < items.length; i++) {
writer.println("<li>" + items[i] + "</li>");
}
writer.println("</ul>");
}
public void close() {
writer.println("</body></html>");
writer.close();
}
public String getResult() {
return filename;
}
}
Directorクラスで具象クラスのメソッドを組み合わせて目的のものを作り上げる。
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.makeTitle("Greeting");
builder.makeString("朝から昼にかけて");
builder.makeItems(new String[]{
"おはようございます。",
"こんにちは。",
});
builder.makeString("夜に");
builder.makeItems(new String[]{
"こんばんは。",
"おやすみなさい。",
"さようなら。",
});
builder.close();
}
}
使用方法
public class Main {
public static void main(String[] args) {
if (args.length != 1) {
usage();
System.exit(0);
}
if (args[0].equals("plain")) {
TextBuilder textbuilder = new TextBuilder();
Director director = new Director(textbuilder);
director.construct();
String result = textbuilder.getResult();
System.out.println(result);
} else if (args[0].equals("html")) {
HTMLBuilder htmlbuilder = new HTMLBuilder();
Director director = new Director(htmlbuilder);
director.construct();
String filename = htmlbuilder.getResult();
System.out.println(filename + "が作成されました。");
} else {
usage();
System.exit(0);
}
}
public static void usage() {
System.out.println("Usage: java Main plain プレーンテキストで文書作成");
System.out.println("Usage: java Main html HTMLファイルで文書作成");
}
}
工場の呼び出し元では、具体的な部品、製品、工場等は利用せず、java Main listfactory.ListFactoryコマンドのように呼び出すクラスを引数で与えており、Class.forName(classname).newInstance()のように生成
抽象的な工場
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.err.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);
}
抽象化部品の例
package factory;
public abstract class Link extends Item {
protected String url;
public Link(String caption, String url) {
super(caption);
this.url = url;
}
}
具体的な工場
package listfactory;
import factory.*;
public class ListFactory extends Factory {
public Link createLink(String caption, String url) {
return new ListLink(caption, url);
}
public Tray createTray(String caption) {
return new ListTray(caption);
}
public Page createPage(String title, String author) {
return new ListPage(title, author);
}
}
具体的な部品の例
package listfactory;
import factory.*;
public class ListLink extends Link {
public ListLink(String caption, String url) {
super(caption, url);
}
public String makeHTML() {
return " <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
}
}
呼び出し元
import factory.*;
public class Main {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java Main class.name.of.ConcreteFactory");
System.out.println("Example 1: java Main listfactory.ListFactory");
System.out.println("Example 2: java Main tablefactory.TableFactory");
System.exit(0);
}
Factory factory = Factory.getFactory(args[0]);
Link asahi = factory.createLink("朝日新聞", "http:
Link yomiuri = factory.createLink("読売新聞", "http:
Link us_yahoo = factory.createLink("Yahoo!", "http:
Link jp_yahoo = factory.createLink("Yahoo!Japan", "http:
Link excite = factory.createLink("Excite", "http:
Link google = factory.createLink("Google", "http:
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", "結城 浩");
page.add(traynews);
page.add(traysearch);
page.output();
}
}
public class Display {
private DisplayImpl impl;
public Display(DisplayImpl impl) {
this.impl = impl;
}
public void open() {
impl.rawOpen();
}
public void print() {
impl.rawPrint();
}
public void close() {
impl.rawClose();
}
public final void display() {
open();
print();
close();
}
}
機能の具象クラス
public class CountDisplay extends Display {
public CountDisplay(DisplayImpl impl) {
super(impl);
}
public void multiDisplay(int times) {
open();
for (int i = 0; i < times; i++) {
print();
}
close();
}
}
実装の抽象クラス
public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}
実装の具象クラス
public class StringDisplayImpl extends DisplayImpl {
private String string;
private int width;
public StringDisplayImpl(String string) {
this.string = string;
this.width = string.getBytes().length;
}
public void rawOpen() {
printLine();
}
public void rawPrint() {
System.out.println("|" + string + "|");
}
public void rawClose() {
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}
使用方法
public class Main {
public static void main(String[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello, Japan."));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
d1.display();
d2.display();
d3.display();
d3.multiDisplay(5);
}
}
10. Strategy
アルゴリズムを切り替え、同じ問題を別の方で解くのを容易にするパターン
委譲というゆるやかな結びつきでアルゴリズムの切り替えが容易
Strategy役の抽象クラス
public interface Strategy {
public abstract Hand nextHand();
public abstract void study(boolean win);
}
Strategy役の具象クラス
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);
}
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]++;
}
}
}
Strategy役を利用するクラス
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();
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.toString());
System.out.println(player2.toString());
}
}
public class Main {
public static void main(String[] args) {
Display b1 = new StringDisplay("Hello, world.");
Display b2 = new SideBorder(b1, '#');
Display b3 = new FullBorder(b2);
b1.show();
b2.show();
b3.show();
Display b4 =
new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(
new StringDisplay("こんにちは。")
),
'*'
)
)
),
'/'
);
b4.show();
}
}
中心となるオブジェクトの元になる抽象化されたクラス
public abstract class Display {
public abstract int getColumns();
public abstract int getRows();
public abstract String getRowText(int row);
public void show() {
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
中心となるオブジェクトの元になる具象化されたクラス
public class StringDisplay extends Display {
private String string;
public StringDisplay(String string) {
this.string = string;
}
public int getColumns() {
return string.getBytes().length;
}
public int getRows() {
return 1;
}
public String getRowText(int row) {
if (row == 0) {
return string;
} else {
return null;
}
}
}
飾り付けの元になる抽象化クラス
public abstract class Border extends Display {
protected Display display;
protected Border(Display display) {
this.display = display;
}
}
飾り付けの元になる具象化クラス
public class SideBorder extends Border {
private char borderChar;
public SideBorder(Display display, char ch) {
super(display);
this.borderChar = ch;
}
public int getColumns() {
return 1 + display.getColumns() + 1;
}
public int getRows() {
return display.getRows();
}
public String getRowText(int row) {
return borderChar + display.getRowText(row) + borderChar;
}
}
public interface Element {
public abstract void accept(Visitor v);
}
抽象クラスで実装を宣言
import java.util.Iterator;
public abstract class Entry implements Element {
public abstract String getName();
public abstract int getSize();
public Entry add(Entry entry) throws FileTreatmentException {
throw new FileTreatmentException();
}
public Iterator iterator() throws FileTreatmentException {
throw new FileTreatmentException();
}
public String toString() {
return getName() + " (" + getSize() + ")";
}
}
ただし実際には具象クラスで定義
public class File extends Entry {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public int getSize() {
return size;
}
public void accept(Visitor v) {
v.visit(this);
}
}
import java.util.Iterator;
import java.util.ArrayList;
public class Directory extends Entry {
private String name;
private ArrayList dir = new ArrayList();
public Directory(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getSize() {
int size = 0;
Iterator it = dir.iterator();
while (it.hasNext()) {
Entry entry = (Entry)it.next();
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) {
dir.add(entry);
return this;
}
public Iterator iterator() {
return dir.iterator();
}
public void accept(Visitor v) {
v.visit(this);
}
}
呼び出し元
public class Main {
public static void main(String[] args) {
try {
System.out.println("Making root entries...");
Directory rootdir = new Directory("root");
Directory bindir = new Directory("bin");
Directory tmpdir = new Directory("tmp");
Directory usrdir = new Directory("usr");
rootdir.add(bindir);
rootdir.add(tmpdir);
rootdir.add(usrdir);
bindir.add(new File("vi", 10000));
bindir.add(new File("latex", 20000));
rootdir.accept(new ListVisitor());
System.out.println("");
System.out.println("Making user entries...");
Directory yuki = new Directory("yuki");
Directory hanako = new Directory("hanako");
Directory tomura = new Directory("tomura");
usrdir.add(yuki);
usrdir.add(hanako);
usrdir.add(tomura);
yuki.add(new File("diary.html", 100));
yuki.add(new File("Composite.java", 200));
hanako.add(new File("memo.tex", 300));
tomura.add(new File("game.doc", 400));
tomura.add(new File("junk.mail", 500));
rootdir.accept(new ListVisitor());
} catch (FileTreatmentException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
Support alice = new NoSupport("Alice");
Support bob = new LimitSupport("Bob", 100);
Support charlie = new SpecialSupport("Charlie", 429);
Support diana = new LimitSupport("Diana", 200);
Support elmo = new OddSupport("Elmo");
Support fred = new LimitSupport("Fred", 300);
alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
for (int i = 0; i < 500; i += 33) {
alice.support(new Trouble(i));
}
}
}
import pagemaker.PageMaker;
public class Main {
public static void main(String[] args) {
PageMaker.makeWelcomePage("hyuki@hyuki.com", "welcome.html");
}
}
public interface Observer {
public abstract void update(NumberGenerator generator);
}
具象化したObserver役のクラス
public class DigitObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
抽象化したSubject役のクラス
import java.util.ArrayList;
import java.util.Iterator;
public abstract class NumberGenerator {
private ArrayList observers = new ArrayList();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
Iterator it = observers.iterator();
while (it.hasNext()) {
Observer o = (Observer)it.next();
o.update(this);
}
}
public abstract int getNumber();
public abstract void execute();
}
具象化したSubject役のクラス
import java.util.Random;
public class RandomNumberGenerator extends NumberGenerator {
private Random random = new Random();
private int number;
public int getNumber() {
return number;
}
public void execute() {
for (int i = 0; i < 20; i++) {
number = random.nextInt(50);
notifyObservers();
}
}
}
呼び出し元
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
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);
}
具象化したState役のクラス
public class DayState implements State {
private static DayState singleton = new DayState();
private DayState() {
}
public static State getInstance() {
return singleton;
}
public void doClock(Context context, int hour) {
if (hour < 9 || 17 <= hour) {
context.changeState(NightState.getInstance());
}
}
public void doUse(Context context) {
context.recordLog("金庫使用(昼間)");
}
public void doAlarm(Context context) {
context.callSecurityCenter("非常ベル(昼間)");
}
public void doPhone(Context context) {
context.callSecurityCenter("通常の通話(昼間)");
}
public String toString() {
return "[昼間]";
}
}
抽象化したContext役のクラス。現在の状態を表すConcreteState役を持つ。
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);
}
具象化したContext役のクラス
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 buttonPhone = new Button("通常通話");
private Button buttonExit = new Button("終了");
private State state = DayState.getInstance();
public SafeFrame(String title) {
super(title);
setBackground(Color.lightGray);
setLayout(new BorderLayout());
add(textClock, BorderLayout.NORTH);
textClock.setEditable(false);
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();
show();
buttonUse.addActionListener(this);
buttonAlarm.addActionListener(this);
buttonPhone.addActionListener(this);
buttonExit.addActionListener(this);
}
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("?");
}
}
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);
}
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");
}
}
20. Flyweight
インスタンスをできるだけ共有させて、無駄にnewしない
管理されているインスタンスはガベージ対象になれない点について注意
Flyweight役。普通に扱うとプログラムが重くなるので共有した方がよいもの。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BigChar {
private char charname;
private String fontdata;
public BigChar(char charname) {
this.charname = charname;
try {
BufferedReader reader = new BufferedReader(
new FileReader("big" + charname + ".txt")
);
String line;
StringBuffer buf = new StringBuffer();
while ((line = reader.readLine()) != null) {
buf.append(line);
buf.append("\n");
}
reader.close();
this.fontdata = buf.toString();
} catch (IOException e) {
this.fontdata = charname + "?";
}
}
public void print() {
System.out.print(fontdata);
}
}
FlyweightFactoryの役。Flyweight役を作る工場。
import java.util.HashMap;
public class BigCharFactory {
private HashMap pool = new HashMap();
private static BigCharFactory singleton = new BigCharFactory();
private BigCharFactory() {
}
public static BigCharFactory getInstance() {
return singleton;
}
public synchronized BigChar getBigChar(char charname) {
BigChar bc = (BigChar)pool.get("" + charname);
if (bc == null) {
bc = new BigChar(charname);
pool.put("" + charname, bc);
}
return bc;
}
}
public class BigString {
private BigChar[] bigchars;
public BigString(String string) {
bigchars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getInstance();
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = factory.getBigChar(string.charAt(i));
}
}
public void print() {
for (int i = 0; i < bigchars.length; i++) {
bigchars[i].print();
}
}
}
21. Proxy
実際に必要な段階になってはじめて、対象のクラスを生成する。
Proxy役とRealSubject役を同一視するためのインターフェースを定義
public interface Printable {
public abstract void setPrinterName(String name);
public abstract String getPrinterName();
public abstract void print(String string);
}
RealSubject役。重い処理の想定。
public class Printer implements Printable {
private String name;
public Printer() {
heavyJob("Printerのインスタンスを生成中");
}
public Printer(String name) {
this.name = name;
heavyJob("Printerのインスタンス(" + name + ")を生成中");
}
public void setPrinterName(String name) {
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String string) {
System.out.println("=== " + name + " ===");
System.out.println(string);
}
private void heavyJob(String msg) {
System.out.print(msg);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.print(".");
}
System.out.println("完了。");
}
}
public class PrinterProxy implements Printable {
private String name;
private Printer real;
public PrinterProxy() {
}
public PrinterProxy(String name) {
this.name = name;
}
public synchronized void setPrinterName(String name) {
if (real != null) {
real.setPrinterName(name);
}
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String string) { // ここがポイント
realize();
real.print(string);
}
private synchronized void realize() {
if (real == null) {
real = new Printer(name);
}
}
}
Client役。Proxyパターンを利用
public class Main {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice");
System.out.println("名前は現在" + p.getPrinterName() + "です。");
p.setPrinterName("Bob");
System.out.println("名前は現在" + p.getPrinterName() + "です。");
p.print("Hello, world.");
}
}
22. Command
命令をオブジェクトとして表現することで、履歴を取ったり再実行を行ったりすることができるようになる
抽象化されたCommand役
package command;
public interface Command {
public abstract void execute();
}
具象化されたCommand役
package drawer;
import command.Command;
import java.awt.Point;
public class DrawCommand implements Command {
protected Drawable drawable;
private Point position;
public DrawCommand(Drawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
public void execute() {
drawable.draw(position.x, position.y);
}
}
命令の受け取り手となるReceiver役
package drawer;
import command.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawCanvas extends Canvas implements Drawable {
private Color color = Color.red;
private int radius = 6;
private MacroCommand history;
public DrawCanvas(int width, int height, MacroCommand history) {
setSize(width, height);
setBackground(Color.white);
this.history = history;
}
public void paint(Graphics g) {
history.execute();
}
public void draw(int x, int y) {
Graphics g = getGraphics();
g.setColor(color);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
上記インターフェイス
package drawer;
public interface Drawable {
public abstract void draw(int x, int y);
}
ConcreteCommand役を生成し、その際にReceiver役を割り当てるClient役
import command.*;
import drawer.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {
private MacroCommand history = new MacroCommand();
private DrawCanvas canvas = new DrawCanvas(400, 400, history);
private JButton clearButton = new JButton("clear");
public Main(String title) {
super(title);
this.addWindowListener(this);
canvas.addMouseMotionListener(this);
clearButton.addActionListener(this);
Box buttonBox = new Box(BoxLayout.X_AXIS);
buttonBox.add(clearButton);
Box mainBox = new Box(BoxLayout.Y_AXIS);
mainBox.add(buttonBox);
mainBox.add(canvas);
getContentPane().add(mainBox);
pack();
show();
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear();
canvas.repaint();
}
}
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
Command cmd = new DrawCommand(canvas, e.getPoint());
history.append(cmd);
cmd.execute();
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
public static void main(String[] args) {
new Main("Command Pattern Sample");
}
}