Hatena::ブログ(Diary)

hiro_saの日記

2013-04-29

Commandパターン

以下参考。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Commandパターン
メソッド呼び出しなどの命令をクラスとして表現するパターン。


public interface Command {
void execute();
}


public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.execute();
}
}


public interface Receiver {
void execute();
}


public class ConcreteReceiver implements Receiver {
@Override
public void execute() {
System.out.println("received command. ");
}
}


public class ClientAndInvoker {
public static void main(String[] args) {
Receiver receiver = new ConcreteReceiver();
Command command = new ConcreteCommand(receiver);
command.execute();
}
}

イベントの発生と、それに対するイベントリスナーの登録とかが、
commandパターンに当てはまるのか?

Flyweightパターン

以下参考。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Flyweightパターン
インスタンスをできるだけ共有し、無駄にインスタンスを生成させないようにするパターン。

IntegerクラスのvalueOfメソッドがこのパターン。


引数で渡された数値が、ある値の範囲内ならば
IntegerCacheクラスで事前に生成してあるIntegerクラスを返却する。
そうでなければ新たにIntegerクラスを生成して返却する。

public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

Proxyパターン

以下参考。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Proxyパターン
・実際に利用するクラスと、全く同じインターフェースを実装する
代理となるクラスを用意し、必要になった時だけ
実際のクラスを生成するようにするパターン。


public interface Subject {
void setText(String text);
void callProxy();
void callEntity();
}


public class Proxy implements Subject {
private Subject realSubject;
private String text;
@Override
public void setText(String text) {
if (realSubject != null) {
realSubject.setText(text);
}
this.text = text;
}
@Override
public void callProxy() {
System.out.println(text);
}
@Override
public synchronized void callEntity() {
if (realSubject == null) {
this.realSubject = new RealSubject();
}
realSubject.callEntity();
}
}


public class RealSubject implements Subject {
private String text;
@Override
public void setText(String text) {
this.text = text;
}
@Override
public void callProxy() {
System.out.println(text);
}
@Override
public void callEntity() {
if (text != null) {
System.out.println("realsubject printed " + text);
} else {
System.out.println("ralsebjcet is first called. reset a text.");
}
}
}


public class Client {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.setText("first called");
proxy.callProxy();
proxy.callEntity();
proxy.setText("second!!");
proxy.callProxy();
proxy.callEntity();
}
}


実行結果
first called
ralsebjcet is first called. reset a text.
second!!
realsubject printed second!!

Stateパターン

以下参考。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Stateパターン
・状態をクラスとして表現する。
→ クラスを切り替えるだけで、状態遷移を表現できるため
別の状態を追加したい時に修正しやすくなる。

気分によって挨拶が変わるコードを実装してみる。


public interface Context {
void greeting();
void moodChange(State state);
}


public class ConcreteContext implements Context {
private State state;
@Override
public void greeting() {
state.reply();
}
@Override
public void moodChange(State state) {
this.state = state;
}
}


public interface State {
void reply();
}


public class FeelingGood implements State{
@Override
public void reply() {
System.out.println("I'm feeling Good!!");
}
}


public class FeelingBad implements State {
@Override
public void reply() {
System.out.println("I'm so tired.");
}
}


public class Main {
public static void main(String[] args) {
Context context = new ConcreteContext();
State bad = new FeelingBad();
State good = new FeelingGood();
context.moodChange(bad);
context.greeting();
context.moodChange(good);
context.greeting();
}
}


実行結果
I'm so tired.
I'm feeling Good!!

気分がそこそこの時や、絶好調の時などを追加したければStateインターフェースを実装する
新しいクラスを追加すれば良い。
各状態に依存するコードをプログラムする時は、各状態を表現するクラスだけ修正すれば良く、
メンテナンスが容易になる。

→ 例えばFeelingGoodの時は元気だから3回挨拶するとか。

2013-03-30

Mementoパターン

以下の書籍を参考にさせて頂きました。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Mementoパターン
・保存と復元を実現するパターン


public class Memento {
int a;
Memento(int a) {
this.a = a;
}
public int getInt() {
return a;
}
}


public class Originator {
private int a;
public Originator(int a) {
this.a = a;
}
public int getInt() {
return a;
}
public int increment() {
return ++a;
}
public Memento createMemento() {
return new Memento(a);
}
public void restoreMemento(Memento memento) {
this.a = memento.a;
}
}


public class CareTaker {
public static void main(String[] args) {
Originator originator = new Originator(100);
Memento memento = originator.createMemento();
for (int i = 0; i < 1000; i++) {
System.out.println(originator.increment());
if (originator.getInt() % 100 == 0) {
originator.restoreMemento(memento);
}
}
}
}


実行結果
101
102
103
104
...
200
101
...
200までいったら100に戻るを繰り返す。

Mementoクラスの変数aとコンストラクタデフォルト修飾子になっている点に注意。
packageは特に書いていないが、MementoとOriginatorが同じpackageで、
CareTakerは別のpackageとなっている想定。
よって、CareTakerはMementoインスタンスを生成することも、
Mementoインスタンスの値を変更することもできない。
(getIntで値を取得できるだけ)

保存も復元もOriginatorを介することでしか行えない。

Observerパターン

以下の書籍を参考にさせて頂きました。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Observerパターン
・観察されている対象の状態が変化した際、
観察者に対して変化が通知される。

JDKにも正にこのパターンのクラスが存在する。
java.util.Observer
java.util.Observable


public interface Observer {
void update(Observable o, Object arg);
}


public class Observable {
private boolean changed = false;
private Vector obs;
public Observable() {
obs = new Vector();
}
...
// 観察者の追加
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
...
public void notifyObservers() {
notifyObservers(null);
}
...
// 通知
public void notifyObservers(Object arg) {
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
// 保持している観察者達に通知を行う
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
...

Observableが普通のクラスなのに注意。

Mediatorパターン

以下の書籍を参考にさせて頂きました。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Mediatorパターン
・各クラス間の複雑な調整を行うパターン。


public interface Mediator {
void createColleagues();
void colleagueChanged();
}


public interface Colleague {
void setMediator(Mediator mediator);
void stateChange();
boolean getState();
void done();
}


public class ConcreteColleagueA implements Colleague {
private Mediator mediator;
private boolean state;
@Override
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
@Override
public void stateChange() {
state = !state;
// 状態が変化したらMediatorに通知
mediator.colleagueChanged();
}
@Override
public boolean getState() {
return state;
}
@Override
public void done() {
System.out.println("ConcreteColleagueA has done");
}
}


public class ConcreteColleagueB implements Colleague {
private Mediator mediator;
private boolean state;
@Override
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
@Override
public void stateChange() {
state = !state;
// 状態が変化したらMediatorに通知
mediator.colleagueChanged();
}
@Override
public boolean getState() {
return state;
}
@Override
public void done() {
System.out.println("ConcreteColleagueB has done");
}
}


public class ConcreateMediator implements Mediator {
private Colleague a;
private Colleague b;
@Override
public void createColleagues() {
this.a = new ConcreteColleagueA();
this.b = new ConcreteColleagueB();
a.setMediator(this);
b.setMediator(this);
}
@Override
public void colleagueChanged() {
// 各クラス間の状態に関する処理は、Mediatorが受け持つ
if (a.getState() && b.getState()) {
a.done();
b.done();
} else if (a.getState()) {
a.done();
} else if (b.getState()) {
b.done();
} ....等々複雑な処理
}
}

Chain of Responsibilityパターン

以下の書籍を参考にさせて頂きました。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Chain of Responsibility
・処理の要求が来たとき、自分で処理できれば自分で行い、
できなければ他のクラスに処理を委譲する。


public abstract class Handler {
private Handler nextHandler;
public Handler setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
return this.nextHandler;
}
protected abstract boolean check(int i);
protected abstract void print();
public void done(int i) {
if (check(i)) {
print();
} else if (nextHandler != null) {
nextHandler.done(i);
} else {
System.out.println("failed.");
}
}
}


public class ConcreteHandlerA extends Handler {
@Override
protected boolean check(int i) {
if (i == 1) {
return true;
} else {
return false;
}
}
@Override
protected void print() {
System.out.println("ConcreteHandlerA has done");
}
}


public class ConcreteHandlerB extends Handler {
@Override
protected boolean check(int i) {
if (i == 2) {
return true;
} else {
return false;
}
}
@Override
protected void print() {
System.out.println("ConcreteHandlerB has done");
}
}


public class ConcreteHandlerC extends Handler {
@Override
protected boolean check(int i) {
if (i == 3) {
return true;
} else {
return false;
}
}
@Override
protected void print() {
System.out.println("ConcreteHandlerC has done");
}
}


public class Main {
public static void main(String[] args) {
Handler a = new ConcreteHandlerA();
Handler b = new ConcreteHandlerB();
Handler c = new ConcreteHandlerC();
a.setNextHandler(b).setNextHandler(c);
a.done(1);
a.done(2);
a.done(3);
a.done(4);
}
}


実行結果
ConcreteHandlerA has done
ConcreteHandlerB has done
ConcreteHandlerC has done
failed.

javaのtry-catchも考え方は同じではないか説。

Visitorパターン

以下の書籍を参考にさせて頂きました。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門



Visitorパターン
・データ構造と、その構造の各要素に対する処理を分離する。


public interface Visitor {
void visit(ObjectStructure o);
void visit(ConcreteElementA a);
void visit(ConcreteElementB b);
}


public interface Element {
void accept(Visitor v);
}


public class ConcreteElementA implements Element{
@Override
public void accept(Visitor v) {
v.visit(this);
}
}


public class ConcreteElementB implements Element{
@Override
public void accept(Visitor v) {
v.visit(this);
}
}


public class ObjectStructure {
private List<Element> list = new ArrayList<>();
public ObjectStructure() {
list.add(new ConcreteElementA());
list.add(new ConcreteElementB());
}
public List<Element> getList() {
return list;
}
}


public class ConcreteVisitor extends Visitor {
@Override
public void visit(ObjectStructure o) {
for (Element e : o.getList()) {
e.accept(this);
}
}
@Override
public void visit(ConcreteElementA a) {
...ConcreteElementAに特化した処理
}
@Override
public void visit(ConcreteElementB B) {
...ConcreteElementBに特化した処理
}
}

2013-03-11

canvasで統計を表示するグラフを描画してみる。

作ってみました。

<code>
<!DOCTYPE html>
<html>
	<head>
		<title>test</title>
		<script>
			const x = 195;
			const y = 100;
			const radius = 80;
			const drawStart = 270;
			const drawEnd = drawStart * 2;
			const anticlockwise = false;
			const strokeColor = 'rgb(0, 0, 255)';
			const circleAngle = 360;
			const graphFont = "bold 12px snas-serif";
			var field1Count = 0;
			var field2Count = 0;
			
			function countUp(button) {
				if (button == 'button1') ++field1Count;
				else if (button == 'button2') ++field2Count;
				document.getElementById('field1').innerHTML = field1Count;
				document.getElementById('field2').innerHTML = field2Count;
				draw();
			}
			function draw() {
				var target = document.getElementById('graph').getContext('2d');
				target.beginPath();
				var startAngle = drawStart;
				var endAngle = drawStart;
				var total = field1Count + field2Count;
				var ratio1 = field1Count / total;
				var ratio2 = field2Count / total;
				endAngle += circleAngle * ratio1;
				target.clearRect(0, 0, 400, 250);
				drawArc(startAngle, endAngle, 'rgba(0, 0, 255, .9)', target
						,'rice' + (ratio1 * 100).toFixed(2) + '%', 300, 125);
				drawArc(endAngle, endAngle + (circleAngle * ratio2), 'rgba(0, 255, 255, .9)', target
						,'bread' + (ratio2 * 100).toFixed(2) + '%', 30, 125);
			}
			function drawArc(startAngle, endAngle, fillColor, target, fillTxt, fillTxtX, fillTxtY) {
				target.moveTo(x, y);
				target.arc(x, y, radius, startAngle * Math.PI / 180, endAngle * Math.PI / 180, anticlockwise);
				target.closePath();
				target.strokeStyle = strokeColor;
				target.fillStyle = fillColor;
				target.fill();
				target.stroke();
				target.font = graphFont;
				target.fillText(fillTxt, fillTxtX, fillTxtY);
			}
		</script>
	</head>
	<body>
		<table>
			<tr>
				<th>statistics.</th>
				<td></td>
				<th>Questions.</th>
			</tr>
			<tr>
				<td rowspan=8>
					<canvas id="graph" width="400" height="250"></canvas>
				</td>
				<td></td>
				<td>Which do you like rice or bread?</td>
			</tr>
			<tr>
				<td colspan=2>
					<span id="field1"></span>
					<input type="button" id="button1" onclick="countUp('button1');"/>&nbsp;I like rice.
				</td>
			</tr>
			<tr>
				<td colspan=2>
					<span id="field2"></span>
					<input type="button" id="button2" onclick="countUp('button2');"/>&nbsp;I like bread.
				</td>
			</tr>
			<tr></tr>
			<tr></tr>
			<tr></tr>
			<tr></tr>
			<tr></tr>
			<tr></tr>
			<tr></tr>
		</table>
	</body>
</html>
</code>

コード的にどうなの?っていう部分と(^^;
一人でポチポチ動かす形式なので、アンケートとして意味不明になっていますがww
複数人で共有できるように徐々に拡張していきたいと思います。
まずはプロトタイプということで。。。

2013-03-03

3月に入って。

今まで毎日無理矢理にでも更新していたのですが、
今月からある程度ネタができてから更新するようにしたいと思います。

引き続き、宜しくお願い致します。

2013-02-28

メモ(jQuery)

これ読んでjQuery.each()の動きがよりイメージできるようになりました。

jQueryのeachの仕組みを徹底的にわかりやすく解説してみた。 - DQNEO起業日記

ホントもう、JavaScriptの本ちゃんと買おうかな。
奥が深いぞ。