面向物件設計模式之---裝飾模式(Decorator Pattern)
裝飾模式給我的感覺就有點像一個人穿衣服,或者從更專業一點的角度來說,有點像Java中檔案讀取時管道要套上一層又一層的“衣服”一樣。這是一個鏈式的過程。
裝飾模式的定義是:
動態地給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
裝飾模式的UML類圖如下:
Componet是定義一個物件介面,可以給這些物件動態地新增職責。ConcreteComponent是定義一個具體的物件,也可以給這個物件新增一些職責。Decorator,裝飾抽象類,繼承了Component,從外類來擴充套件Component類的功能,但對於Component來說,是無需知道Decorator的存在的。至於ConcentrateDecorator就是具體的裝飾物件,起到給Component新增職責的功能。——《大話設計模式》
有沒有看了這段話還是有點暈?還是回到本文開頭提到的穿衣服 的應用場景,我是這麼理解的:比如人穿衣服,寵物也可以穿衣服,人和寵物都可以算是生物。所以,生物就是這個Component介面,人或者是寵物就是ConcentrateComponent類;衣服就是Decorator類,而具體穿了什麼衣服就是ConcreteDecorator類。
我們現在想把小明穿衣服這個場景模擬成程式碼,有時如果ConcreteComponent類只有一個,並且沒有抽象的話,就不需要Component介面了 比如我們實現的只有人穿衣服,就可以直接把Component和ConcreteComponent類進行合併,只要有一個Person類就行了。如果Decorator類有類似的情況也可以如此操作。
人穿衣服 這個事件的UML類圖如下:
這裡我們就拿了兩週衣服,一種是T恤,另外一種是喇叭褲。實現的程式碼如下:
import java.util.*;
//人類
class Person
{
private String name;
public Person(String name)
{
this.name = name;
}
public Person(){}
public void show()
{
System.out.println(this.name+"的裝扮");
}
}
//服飾類
class Finery extends Person
{
protected Person component;
public Finery()
{
super();
}
public void decorate(Person component)
{
this.component = component;
}
public void show()
{
if(this.component != null)
{
this.component.show();
}
}
}
//具體的服飾
class TShirts extends Finery
{
public void show()
{
System.out.print("穿大T恤");
super.show();
}
}
class BigTrouser extends Finery
{
public void show()
{
System.out.print("穿喇叭褲");
super.show();
}
}
public class Main
{
public static void main(String[] args)
{
Person p = new Person("小明");
TShirts ts = new TShirts();
BigTrouser bt = new BigTrouser();
ts.decorate(p);
bt.decorate(ts);
bt.show();
}
}
上述程式碼執行的結果為:
穿喇叭褲穿大T恤小明的裝扮
最後我想補充的是這段程式碼的執行過程,為什麼會有這樣的執行結果
首先,先看main方法的頭三行。
Person p = new Person("小明"); TShirts ts = new TShirts(); BigTrouser bt = new BigTrouser();
它們分別例項化了人、T恤、喇叭褲物件
- 接著,人先穿上了喇叭褲,再穿上了T恤。
- 然後,重點在那個show方法。
a.從程式碼的層面來看,是從喇叭褲物件來呼叫show方法的,所以,先輸出了穿喇叭褲。
我們不妨看看最先呼叫show方法的這個喇叭褲類物件的結構:
可以發現,喇叭褲套了T恤物件,T恤物件又包了人。可以說是非常形象了,人就是被衣服包著嘛~
b.在喇叭褲類的show方法中,呼叫了super.show()。因為喇叭褲類的基類是服飾類,所以轉而呼叫服飾類的show(),注意:此時有一個向上物件轉型,將喇叭褲向上轉型為服飾,又因為這兩個類在屬性上是沒有差異的,所以,當在基類的show方法中呼叫this.component.show()時,就相當於往前進一步,進入了T恤物件,直到this.component物件為空時結束。