標籤: 前端 設計模式 裝飾者模式 typescript Decorator Wrapper
如果下面的代碼你能輕易閱讀,那麼你已經熟悉裝飾者模式,可以接着學習其他的設計模式。
裝飾者模式
裝飾者模式: 裝飾模式是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
實際場景
我們購買一件白色/黑色的衣服。購買的主體是一件衣服。而白色和黑色是衣服的裝飾,就像是條紋的/碎花的。
這時我們常常把白色/黑色,條紋/碎花作爲裝飾器裝飾在衣服上。
如果需要爲類增添特性或者職責,而從該類派生子類的解決辦法並不實際的話,就應該使用裝飾者模式。
裝飾者模式的結構
- 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。
- 裝飾對象包含一個真實對象的引用(reference)
- 裝飾對象接受所有來自客戶端的請求。它把這些請求轉發給真實的對象。
- 裝飾對象可以在轉發這些請求以前或以後增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。
裝飾者模式的例子
製作一件有顏色的衣服
衣服的接口
/* i-clothes.ts */
export default interface IClothes {
setColor: (color) => any;
setType: (type) => any;
}
一個衣服的類實現衣服的接口,一個修改顏色的類實現衣服的接口
/* clothes-class.ts */
import IClothes from './i-clothes';
export class Clothes implements IClothes {
public color: string;
public type: string;
public setColor (color) {
this.color = color;
}
public setType (type) {
this.type = type;
}
}
export class ChangeColor implements IClothes {
public clothes: IClothes;
constructor (clothes: IClothes) {
// 對原對象進行'引用'
this.clothes = clothes;
}
public setColor (color) {
console.log('will be overridden')
}
public setType (type) {
// 將操作轉發給原對象
this.clothes.setType(type);
}
}
兩個顏色的類繼承衣服的接口
/* color-class.ts */
import { ChangeColor } from './clothes-class';
import IClothes from './i-clothes';
export class WhiteClothes extends ChangeColor {
constructor (clothes: IClothes) {
super(clothes);
}
public setColor () {
this.clothes.setColor('white');
}
// 在裝飾類中添加更多方法
public whiteFun () {
console.log('This is white function');
}
}
export class BlackClothes extends ChangeColor {
constructor (clothes: IClothes) {
super(clothes);
}
public setColor () {
this.clothes.setColor('black');
}
public blackFun () {
console.log('This is black function')
}
}
客戶端的實現
/* client.ts */
import { Clothes } from './clothes-class';
import { BlackClothes, WhiteClothes } from './color-class';
import IClothes from './i-clothes';
class Client {
public getBlackClothesAndWhiteClothes () {
const clothes: IClothes = new Clothes();
const whiteClothes: WhiteClothes = new WhiteClothes(clothes);
whiteClothes.setColor();
whiteClothes.whiteFun();
const blackClothes: BlackClothes = new BlackClothes(clothes);
blackClothes.setColor();
blackClothes.blackFun();
}
}
new Client().getBlackClothesAndWhiteClothes();
當衣服是白色的時候會擁有白色衣服的特性和方法,當衣服變成黑色的時候,會擁有黑色衣服的特性和方法。
裝飾者模式的利弊
優點
- Decorator模式與繼承關係的目的都是要擴展對象的功能,但是Decorator可以提供比繼承更多的靈活性。
- 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行爲的組合。
缺點
- 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。
- 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程序變得很複雜。
- 裝飾模式是針對抽象組件(Component)類型編程。但是,如果你要針對具體組件編程時,就應該重新思考你的應用架構,以及裝飾者是否合適。當然也可以改變Component接口,增加新的公開的行爲,實現“半透明”的裝飾者模式。在實際項目中要做出最佳選擇。