設計模式之「Decorator」註疏#02

前序文章《設計模式之「Observer」註疏#01》

裝飾模式在某種意義上來說也是挺原始的,

  1. 它首先需要一個你被裝飾的基礎類
  2. 再來是需要一個基於這個基礎類的原始包裝器,可以看作是其它包裝器的基礎類
  3. 進而通過繼承這個包裝器,來構建出多個具有各自功能的特定包裝器
  4. 最後,是通過層層組合這些包裝器(通過一層層地使用構造函數的方式),來構建出你最終需要的包含多個功能的產品類

一開始接觸這一過程時,不免會感覺繁雜、手足無措。不就是一個不斷裝飾、不斷包裹的過程么,為何需要這麼多的步驟呢?

那麼,我可以首先給出一個直觀解釋,並且通過這個直觀解釋,可以在一定程度上去解釋這裡所謂的裝飾模式的「原始」表示什麼意思。

我們可以把一般的抽象的「裝飾過程」想像為:不斷地往被裝飾物上面添加裝飾物件的過程。(特別地,我們在這裡考察一個特殊的裝飾過程:往牆壁上不斷添加各色牆紙的過程,來作為例子。)

(一)

那麼,從一般性的裝飾過程來看,首先要解決的問題便是:到底為什麼物件做裝飾呢?你是為一盞檯燈做裝飾,還是為一張桌子做裝飾,又或是為了一面牆做裝飾?所以,我們需要一個基礎類來決定,被裝飾物到底是什麼。(在這裡,我們的被裝飾物是一面牆,所以,我們需要聲明「牆」這個類作為我們的基礎類。)

(二)

有了裝飾的目標之後,下一個要解決的問題是拿什麼來做裝飾呢?你是用一朵花來做裝飾呢?還是用一個氣球?又或是用一張海報來做裝飾?並且,你選中的這個裝飾物還和你的被裝飾物牢牢相關。例如,裝飾汽車的花朵和裝飾卧室的花朵品種可能並不相同;裝飾戶外的氣球和裝飾辦公室的氣球風格,也可能不同。

所以,你不僅要決定做裝飾器物(也即是裝飾器decorator)的品種,還得要讓這個裝飾器牢牢地和你的被裝飾物相關。(在這裡,我們需要裝飾牆壁的牆紙。所以你需要建立一個「牆紙」類,並且它是同你的被裝飾物「牆」相關)

需要注意的是,這一步的裝飾物是一個泛指。例如裝飾汽車的花朵、裝飾辦公室的氣球、裝飾牆壁的牆紙。可是,這個花朵是什麼顏色的、氣球是什麼形狀的、牆紙是什麼花紋的,我們並不知道。所以在這一步,聲明的僅僅是一個具備功能性泛指的裝飾器基礎類。

(三)

自然地,下一步的工作便是細化你的裝飾器。在這個一般性的裝飾器下,例如牆紙,你的這個牆紙到底是什麼花紋、什麼顏色、有什麼特殊功效。這就可以通過構建一個個具體的子類來實現。

(四)

最後,有了被裝飾的物件、有了各種裝飾器,那麼,就可以通過原始的被裝飾物,以及各個裝飾器的層層嵌套構造函數,來構建出一個具備各種特定功能的產品。

所以,整體考察下來,這個過程還是挺直觀的。但是,說其「原始」,是因為你的很多特殊裝飾器的構造都必須要通過層層嵌套才能夠創造。例如,我裝飾汽車的花朵為什麼不可以直接拿去裝飾卧室?從現實直觀上,我們是可以這樣做的,但是它卻不能在「類」的構建體系中實現一個方便的遷移,不得不從最開始被裝飾物出發,一層層地添加裝飾物來實現最後的你需要的產品。

// 1. Basic class, the decorated thingpublic class Wall { private String _name; public Wall(); public void set(String name) { _name = name; } public String get() { return _name; }}// 2. General decorator classpublic class WallPaper extends Wall { protected Wall _wall; public WallPaper(Wall wall) { _wall = wall; } public void set(String name) { _wall.set(name); } public String get() { return _wall.get(); }}// 3.1 Specific decorator: red wall paperpublic class RedWallPaper extends WallPaper { public RedWallPaper(Wall wall) { super(wall); } // ... other specific features}// 3.2 Specific decorator: blue wall paperpublic class BlueWallPaper extends WallPaper { public BlueWallPaper(Wall wall) { super(wall); } // ... other specific features}// 4. Final decoration: colorful wallpublic class Decoration { public static void main(String[] args) { BlueWallPaper ColorfulWall = new BlueWallPaper( new RedWallPaper(new Wall()) ); }}

再來看更為一般和抽象的來自Thinking in Java裝飾模式的代碼示例:

// 1. Basic class, the decorated thingclass Basic { private String value; public void set(String val) { value = val; } public String get() { return value; }}// 2. General decorator classclass Decorator extends Basic { protected Basic basic; public Decorator(Basic basic) { this.basic = basic; } public void set(String val) { basic.set(val); } public String get() { return basic.get(); }}// 3.1 Specific decoratorclass TimeStamped extends Decorator { private final long timeStamp; public TimeStamped(Basic basic) { super(basic); timeStamped = new Date().getTime(); } public long getStamp() { return timeStamp; }}// 3.2 Specific decoratorclass SerialNumbered extends Decorator { private static long counter = 1; private final long serialNumber = counter++; public SerialNumbered(Basic basic) { super(basic); } public getSerialNumber() { return serialNumber; }}// 4. Decorationpublic class Decoration { public static void main(String[] args) { TimeStamped t = new TimeStamped( new Basic() ); TimeStamped t2 = new TimeStamped( new SerialNumbered(new Basic()) ); //! t2.getSerialNumber(); // Not available SerialNumbered s = new SerialNumbered( new Basic() ); SerialNumbered s2 = new SerialNumbered( new TimeStamped(new Basic()) ); //! s2.getStamp(); // Not available }}

這樣,裝飾模式應該就可以理解了。

近期回顧

《由閱讀源碼想到 | 下篇》

《由閱讀源碼想到》

《志玲姐姐的《十三邀》》

如果你喜歡我的文章或分享,請長按下面的二維碼關注我的微信公眾號,謝謝!

VIP讚賞專區


推薦閱讀:

面向新手的雜談:Flyweight(續)

TAG:原創文章 | 設計模式 |