オブジェクト間の相互作用をカプセル化するオブジェクトを定義します。
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;
public class MediatorSample {
public static void main(String[] args) {
Dialog_ConcreteMediator dialog = new MediatorSample().new Dialog_ConcreteMediator();
dialog.setVisible(true);
}
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);
text = new TextField();
text.setBounds(20, 50, 200, 25);
text.addActionListener(this);
this.add(text); buttonAdd = new Button("Add");
buttonAdd.setBounds(220, 50, 50, 25);
buttonAdd.addActionListener(this);
this.add(buttonAdd); list = new List(5);
list.setBounds(20, 80, 250, 100);
list.addActionListener(this);
this.add(list); buttonClose = new Button("Close");
buttonClose.setBounds(220, 185, 50, 25);
buttonClose.addActionListener(this);
this.add(buttonClose); }
public void actionPerformed(ActionEvent e) {
System.out.println("dialog.actionPerformed(): from " + ((Component)e.getSource()).getName());
if (this.buttonAdd == e.getSource() || this.text == e.getSource()) { if (!this.text.getText().isEmpty()) {
this.list.add(this.text.getText());
}
} else if (this.list == e.getSource()) { this.text.setText(this.list.getSelectedItem());
} else if (this.buttonClose == e.getSource()) { this.dispose();
}
}
}
}