1. 程式人生 > >面向物件設計模式之---裝飾模式(Decorator Pattern)

面向物件設計模式之---裝飾模式(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物件為空時結束。