目的
讓多個物件都有機會處理某一訊息,以降低訊息發送者和接收者之間的耦合關係。它將接收者物件串連起來,讓訊息流經其中,直到被處理了為止。
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
適用
- 希望訊息不只有一個物件可處理,至於哪個會雀層中選,事先並不知情;系統會自動挑選。
- 希望能將某一訊息丟給好幾個物件,不必指明誰是接收者。
- 希望能動態指定哪些物件可處理某一訊息。
結構及成員
Collaborations: 當Client發出訊息後,訊息會在串鏈裡流竄,直到有個ConcreteHandler物件處理為止。
影響結果
好處
壞處
實作
製作後繼者串鏈,大致有兩種做法
- 定義新的連結,較常使用(通常寫在Handler或ConcreteHandler裡)。
- 使用既有的連結,重複利用(指標和Composite Pattern)。
連接後繼者
- 如果沒有既存的連結可用,就得自己定義。也就是說Handler要定義訊息介面,也要維護後繼者。
- 因此Handler通常會提供一個內定的HandleRequest()版本,如果子類別ConcreteHandler不想處理這個訊息,就不必改寫這操作,直接沿用。
表達訊息?
- 方法一:寫成方法(如:HandleHelp()),既方便又簡單,但只能傳遞定義過且數目固定的類型。
- 方法二:製作一個可接收訊息代碼參數的函數,並用另一個訊息物件來承載參數。(如:定義一個Request類別,再用子類別定義各種新的訊息類型參數)。
Example: MailHandler
// 所有處理郵件的子類別要繼承的介面
public abstract class MailHandler {
// 每個處理郵件類別都要記錄下一個
// 能處理的人是誰
protected MailHandler mHandler;
public MailHandler(MailHandler handler) {
mHandler = handler;
}
public void toNext(Mail mail) {
if(mHandler != null) {
mHandler.handleMail(mail);
} else {
// 沒有後繼者, 表示是尾端了
// 通常可以用最一般化的處理
}
}
public abstract void handleMail(Mail mail);
}
public class SpamMailHandler extneds MailHandler {
SpamMailHandler(MailHandler handler){
super(handler);
}
@Override
public void handleMail(Mail mail) {
// 假設已經能知道郵件分類了
if(mail.isSpam()) {
// 處理垃圾信
} else {
toNext(mail);
}
}
}
public class ThankMailHandler extneds MailHandler {
...
}
public class ComplainMailHandler extneds MailHandler {
...
}
public class GeneralMailHandler extends MailHandler {
...
}
public class Main {
public static void main(String[] args) {
// 可以這樣使用
MailHandler handler = new ThankMailHandler(
new ComplainMailHandler(
new SpamMailHandler(
new GeneralMailHandler(null))));
// 假設有一封郵件要處理
Mail mail = new Mail(...);
handler.hanldeMail(mail);
}
}