2015年6月20日土曜日

1-17. Mediator パターン

オブジェクト間の相互作用をカプセル化するオブジェクトを定義します。
Mediator は相互参照による結合度を弱め、それにより独立させることができます。



クラスが増えてオブジェクト間の相互参照が増えると、プログラムが複雑になるだけでなく、
単独でクラスを再利用することが難しくなります。
Mediator パターンでは、Mediator を介することで Colleague 間の結合度を弱めます。
void client() {
	Mediator mediator = new ConcreteMediator();
	Colleague colleague1 = new ConcreteColleague(mediator, "colleague1");
	mediator.addColleague(colleague1);
	Colleague colleague2 = new ConcreteColleague(mediator, "colleague2");
	mediator.addColleague(colleague2);
	colleague1.needsAdvice();
	colleague2.needsAdvice();
}
interface Mediator {
	public void addColleague(Colleague colleague);
	public void consultation(Colleague colleague);
}
interface Colleague {
	public void needsAdvice();
	public void advice(Colleague colleague);
}
class ConcreteMediator implements Mediator {
	private LinkedList<Colleague> colleagues = new LinkedList<>();
	public void addColleague(Colleague colleague) {
		this.colleagues.add(colleague);
	}
	public void consultation(Colleague colleague) {
		System.out.println("mediator.consultation(): from " + colleague);
		for (Colleague c: this.colleagues) {
			c.advice(colleague);
		}
	}
}
class ConcreteColleague implements Colleague {
	private Mediator mediator;
	private String name;
	public ConcreteColleague(Mediator mediator, String name) {
		this.mediator = mediator;
		this.name = name;
	}
	public void needsAdvice() {
		this.mediator.consultation(this);
	}
	public void advice(Colleague colleague) {
		System.out.println(this + ".advice(): from " + colleague);
	}
	public String toString() {
		return this.name;
	}
}
出力結果:
mediator.consultation(): from colleague1
colleague1.advice(): from colleague1
colleague2.advice(): from colleague1
mediator.consultation(): from colleague2
colleague1.advice(): from colleague2
colleague2.advice(): from colleague2
サンプルプログラムは、ダイアログの例です。
ここではダイアログが Mediator、ボタン・テキストボックス・リストといった部品が Colleague に相当
します。
テキストを入力して Add ボタンを押すとリストに追加されますが、Colleague である部品がほかの
部品を直接操作することはせず、一度 Mediator であるダイアログを介して操作を行います。
Add ボタンを押す -> Button.processActionEvent(Colleague.needsAdvice() に相当)
-> Dialog_ConcreteMediator.actionPerformed()(ConcreteMediator.consultation() に相当)
-> テキストボックスのテキストを取得し、リストに追加(ConcreteColleague.advice() に相当)
ボタン->ダイアログへの呼び出しは、標準ライブラリの Button クラスが行っています。
Button.addActionListener() によって ActionListener インターフェースを実装したダイアログを
登録することで、ボタンでアクションイベントが発生した際に
Dialog_ConcreteMediator.actionPerformed() が呼び出されます。
実行結果:
dialog.actionPerformed(): from button0
dialog.actionPerformed(): from button0
dialog.actionPerformed(): from list0
dialog.actionPerformed(): from button1

package design_pattern;

import java.awt.Button;
import java.awt.Component;
import java.awt.Frame;
import java.awt.List;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * Mediator
 * GoF
 * 
 * オブジェクト間の相互作用をカプセル化するオブジェクトを定義します。
 * Mediator は相互参照による結合度を弱め、それにより独立させることができます。
 * 
 * @author 2015/05/30 matsushima
 *
 */
public class MediatorSample {
	/**
	 * main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// ConcreteMediator: dialog
		Dialog_ConcreteMediator dialog = new MediatorSample().new Dialog_ConcreteMediator();
		dialog.setVisible(true);
	}

	/** ConcreteMediator: ダイアログ。 */
	public class Dialog_ConcreteMediator extends Frame implements ActionListener {
		private static final long serialVersionUID = 1L;
		private TextField text;
		private List list;
		private Button buttonAdd, buttonClose;
		public Dialog_ConcreteMediator() {
			super("MediatorSample");
			setLayout(null);
			addWindowListener(new WindowAdapter() {
				public void windowClosing(WindowEvent e) { System.exit(0); }
			});
			this.setSize(290, 230);
			// ConcreteColleague: text
			text = new TextField();
			text.setBounds(20, 50, 200, 25);
			text.addActionListener(this);
			this.add(text); // Mediator.addColleague に相当。
			// ConcreteColleague: buttonAdd
			buttonAdd = new Button("Add");
			buttonAdd.setBounds(220, 50, 50, 25);
			buttonAdd.addActionListener(this);
			this.add(buttonAdd); // Mediator.addColleague に相当。
			// ConcreteColleague: list
			list = new List(5);
			list.setBounds(20, 80, 250, 100);
			list.addActionListener(this);
			this.add(list); // Mediator.addColleague に相当。
			// ConcreteColleague: buttonClose
			buttonClose = new Button("Close");
			buttonClose.setBounds(220, 185, 50, 25);
			buttonClose.addActionListener(this);
			this.add(buttonClose); // Mediator.CloseColleague に相当。
		}
		/** ConcreteMediator.consultation() に相当。 */
		public void actionPerformed(ActionEvent e) {
			//System.out.println(e);
			System.out.println("dialog.actionPerformed(): from " + ((Component)e.getSource()).getName());
			if (this.buttonAdd == e.getSource() // buttonAdd click
					|| this.text == e.getSource()) { // text enter
				if (!this.text.getText().isEmpty()) {
					this.list.add(this.text.getText());
				}
			} else if (this.list == e.getSource()) { // list double-click
				this.text.setText(this.list.getSelectedItem());
			} else if (this.buttonClose == e.getSource()) { // buttonClose click
				this.dispose();
			}
		}
	}
	
	///** Mediator: ConcreteColleague からのイベント受け取り。 */
	//public interface ActionListener extends EventListener {
	//    /** Mediator.consultation() に相当。 */
	//    public void actionPerformed(ActionEvent e);
	//}

	///** ConcreteColleague: ボタン。 */
	//public class Button(or TextField, List) extends Component {
	//	/** ConcreteColleague.needsAdvice() に相当。 */
	//	protected void processActionEvent(ActionEvent e) {
	//	    ActionListener listener = actionListener;
	//	    if (listener != null) {
	//	        listener.actionPerformed(e); // ConcreteMediator.consultation() に相当
	//	    }
	//	}
	//}
}

0 件のコメント:

コメントを投稿