有天朋友問我,什麼是裝飾器模式。
我不假思索地回答在不影響架構的情況下加新功能。
朋友再問:那為什麼不寫一起
接著我陷入了沉思...
允許動態地將行為新增到單個物件,而不會影響同一類中其他物件的行為。
這邊簡單的說就是,一個動態新增功能的方法。
很多裝飾器模式的教學都會提到,這是一個動態新增功能的方法。
卻很少有說明到為什麼要這麼做,加上一些不太貼近真實開發的範例,
導致很多人看到裝飾器模式也是一知半解。
(意思是,為了精準表達裝飾器模式的運作,而比較少提其內涵)
這個模式主要的作用是在維持單一職責(SRP)的情況下,
連動不同類別所提供的功能。
假設我們今天要開發一個登入系統,
當使用者送出登入事件後,
會先簡訊通知使用者,
再寄送e-mail,
最後才會進行登入。
我們應該如何設計呢?
// 建立裝飾器模式串接的結構
abstract class AbstractDecorator{
// 串接的對象
protected AbstractDecorator decorator;
public AbstractDecorator setDecorator(AbstractDecorator decorator){
this.decorator = decorator;
return this;
}
// 當 decorator 不為null的時候 會先執行串接對象的內容
public override void Notify(){
if (decorator != null){
decorator.Notify();
}
}
}
//實作出 LoginSystem、EmailSystem、SMSSystem
class LoginSystem:Decorator{
//這邊其實不需要覆寫override
public override void Notify(){
base.Notify();
}
public void signin(){
//TODO: 實踐登入內容
}
}
class EmailSystem:Decorator{
public override void Notify(){
//執行串接對象的內容
//等效於
// if (decorator !=null){
// decorator.Notify();
// }
base.Notify();
sendEmail();
}
private void sendEmail(){
//TODO: 寄信到email通知使用者
}
}
class SMSSystem:Decorator{
public override void Notify(){
//執行串接對象的內容
//等效於
// if (decorator !=null){
// decorator.Notify();
// }
base.Notify();
sendEmail();
}
private void sendSMS(){
//TODO: 寄簡訊通知使用者
}
}
public static void main(){
// 建立物件
var login_sys = new LoginSystem();
var email_sys = new EmailSystem();
var sms_sys = new SMSSystem();
// 將功能串接起來
// 等效於
// login_sys.setDecorator(email_sys);
// email_sys.setDecorator(sms_sys);
login_sys.setDecorator(email_sys.setDecorator(sms_sys));
// 設定完成後,只需要對 login_sys進行操作即可
// 之後凡是使用到 Notify 就會連動寄信及簡訊
//通知使用者
login_sys.Notify();
//登入
login_sys.signin();
}
其實,裝飾器模式與行為型設計模式中的責任鏈模式(Chain Of Responsibility Pattern)
也是十分的相似。這兩者的關係有點類似於橋接模式與策略模式之間的關係。
學習的過程中可以多去對比這四個模式的區別,
可以更好理解個模式的差異及結構型與行為型的區別。
這邊設計的裝飾器模式架構,並不是特別的完整。
其中一部分原因是因為如果將架構設計的過於複雜有礙於對整體的了解,
(另一部分原因是因為我懶)
之後對於裝飾器模式的用途有比較深入的了解後,
可以去看看GOF對裝飾器模式定義的完整結構。