2011年4月19日 星期二

GoF Behavioral - Mediator Pattern


  • Intent


to define an object that encapsulates how a set of objects interacts. It helps to promote a looser coupling by keeping objects from referring to each other explicitly, therefore allowing any interaction to vary independently.

通常一個系統都是由多個物件組成,有的甚至上達千個以上,所以對於系統功能的商業邏輯以及資料運算很自然地就充斥在各個物件之間,然而當開發了越來越多的功能,伴隨著大量的物件數量的激增,在維護上或者重構上面臨到的困難便是,每個物件之間的溝通問題越來越難解,甚至會到達難以閱讀程式碼的窘境,最後終究會變成無法修正問題,因為每當要改一個bug,就得牽動了很多的物件關聯,我想這個pattern應該很適合用在 我正在進行的案子,老舊的那一大坨系統每次都會看到頭暈。

那到底該怎麼做? Mediator pattern在物件之間的訊息溝通,純粹就是透過 Mediator obj,把相關訊息包進這個mediator object,那麼從此每個物件不再是直接的跟別人面對面的溝通,凡事都透過mediator這個中介者,如此也降低了維護的複雜度以及耦合度。

補充一下 Head First Design Pattern當中所說到的資訊:

"居間協調者(mediator)"將相關的物件之間,複雜的溝通和控制方式予以簡化

而到底該怎麼做?

1. 讓每個物件都在改變自己狀態時,通知居間協調者

2. 讓每個物件都會居間協調者所發出的請求做出回應

綜觀上述兩點,可以發現 居間協調者與其他物件是彼此相依


  • Benefits




  1. 透過集中式的管理,處理訊息傳遞

  2. 減少個物件之間的溝通複雜度

  3. 每個實際運作的物件內容不需要特別去處理交互溝通的內容


以下補充自Head First Design Pattern

藉由將物件彼此鬆綁,可以增加物件的再利用性。

藉由將控制邏輯中央集權化,可以簡化系統維護。

可以讓物件之間所傳遞的訊息,變得簡單而且大幅減少。

而居間協調者常常是用來協調相關的GUI元件,但缺點是如果設計不當的話,協調者本身會變得太過複雜。


  • 適用情境




  1. 一群物件集合是以相當複雜的運作模式在提供服務,但是有一組規畫良好的溝通方式定義

  2. 需要有一些特定客製化的物件之間的複雜操作關係,但不想透過繼承方式來進行。這通常都是用在結構化的訊息傳遞系統中。




  • Class Diagram




[caption id="attachment_246" align="alignnone" width="562" caption="Mediator Pattern"]Mediator Pattern[/caption]


  • Sample Code



package mediatorpattern;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

interface Command {
void execute();
}

class BtnView extends JButton implements Command {

Mediator med;

BtnView(ActionListener al, Mediator m) {
super("view");
addActionListener(al);
med = m;
med.registerView(this);
}

@Override
public void execute() {
// TODO Auto-generated method stub
med.view();
}
}

class BtnSearch extends JButton implements Command {
Mediator med;

BtnSearch(ActionListener al, Mediator m) {
super("search");
addActionListener(al);
med = m;
med.registerSearch(this);
}

@Override
public void execute() {
// TODO Auto-generated method stub
med.search();
}
}

class BtnBook extends JButton implements Command {
Mediator med;

BtnBook(ActionListener al, Mediator m) {
super("Book");
addActionListener(al);
med = m;
med.registerBook(this);
}

@Override
public void execute() {
// TODO Auto-generated method stub
med.book();
}
}

class LblDisplay extends JLabel {
Mediator med;

LblDisplay(Mediator m) {
super("Just start ...");
med = m;
med.registerDisplay(this);
setFont(new Font("Arial", Font.BOLD, 24));
}

}

class Mediator {
BtnView btnView;
BtnSearch btnSearch;
BtnBook btnBook;
LblDisplay show;

void registerView(BtnView v) {
this.btnView = v;
}

void registerSearch(BtnSearch s) {
this.btnSearch = s;
}

void registerBook(BtnBook b) {
this.btnBook = b;
}

void registerDisplay(LblDisplay lbl) {
this.show = lbl;
}

void book() {
btnBook.setEnabled(false);
btnView.setEnabled(true);
btnSearch.setEnabled(true);
show.setText("booking...");
}

void view() {
btnView.setEnabled(false);
btnSearch.setEnabled(true);
btnBook.setEnabled(true);
show.setText("viewing...");
}

void search() {
btnSearch.setEnabled(false);
btnView.setEnabled(true);
btnBook.setEnabled(true);
show.setText("searching...");
}
}

class MediatorDemo extends JFrame implements ActionListener {
Mediator med = new Mediator();

MediatorDemo() {
JPanel p = new JPanel();
p.add(new BtnView(this, med));
p.add(new BtnBook(this, med));
p.add(new BtnSearch(this, med));
getContentPane().add(new LblDisplay(med), "North");
getContentPane().add(p, "South");
setSize(400, 200);
setVisible(true);
}

public void actionPerformed(ActionEvent ae) {
Command comd = (Command) ae.getSource();
comd.execute();
}
}

public class MediatorPattern {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new MediatorDemo();
}

}

沒有留言: