天天看點

裝飾模式(Decorator Pattern) 裝飾模式的優點 裝飾模式的缺點

裝飾模式:

以對客戶透明的方式動态地給一個對象附加上更多的責任。它是通過建立一個包裝對象,也就是裝飾來包裹真實的對象。若要擴充功能,裝飾者比繼承提供了更有彈性的替代方案。

裝飾模式的類圖如下:

裝飾模式(Decorator Pattern) 裝飾模式的優點 裝飾模式的缺點

在裝飾模式中的角色有:

  ●  抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。

  ●  具體構件(ConcreteComponent)角色:定義一個将要接收附加責任的類。

  ●  裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,并定義一個與抽象構件接口一緻的接口。

  ●  具體裝飾(ConcreteDecorator)角色:負責給構件對象“貼上”附加的責任。

源代碼:

抽象建構component:

public interface Animal {
    void behavior();
}      

具體建構concreteComponent:

public class Dog implements Animal {
    public void behavior() {
        System.out.println("小狗會跑");
    }
}      

裝飾者decorator:

public class Sports implements Animal {
    private Animal animal;

    public Sports(Animal animal){
        this.animal = animal;
    }

    public void behavior(){
        this.animal.behavior();
    }
}      

具體狀态 concreteDecorator:

public class Jump extends Sports {
    public Jump(Animal animal) {
        super(animal);
    }

    @Override
    public void behavior() {
        super.behavior();
        System.out.println("會跳");
    }
}      
public class Sleep extends Sports{
    public Sleep(Animal animal) {
        super(animal);
    }

    public void behavior(){
        super.behavior();
        System.out.println("累了會睡覺");
    }

}      
public class Thought extends Sports{
    public Thought(Animal animal) {
        super(animal);
    }

    public void think(){
        System.out.println("這是一隻會思考的動物");
    }
}      

測試代碼:

public class Test {
    public static void main(String[] args) {
        //透明的裝飾模式
        Animal animal = new Dog();
        animal.behavior();
        System.out.println();
        animal = new Jump(animal);
        animal.behavior();
        System.out.println();
        animal = new Sleep(animal);
        animal.behavior();
        System.out.println();
        //半透明的裝飾模式
        Thought thought = new Thought(new Dog());
        thought.think();
        thought.behavior();
    }
}      

輸出結果:

小狗會跑

小狗會跑

會跳

小狗會跑

會跳

累了會睡覺

小狗會跑

這是一隻會思考的動物

可以看到我在測試代碼裡面分為了2個部分:透明的狀态模式,半透明的裝飾模式。下面就以這2個部分來介紹一下裝飾模式的使用。

我們定義了Dog類,定義了他的行為是“小狗會跑”。同時,我們又定義了一下裝飾者Jump,Sleep,通過下面這個代碼活動一個動物

Animal sleep = new Sleep(new Jump(new Dog()));      

這隻動物的行為其實就是測試方法中輸出的:

小狗會跑

會跳

累了會睡覺

這就是文字開頭說的通過建立一個包裝對象,也就是裝飾來包裹真實的對象,動态地給一個對象附加上更多的責任。

這裡動态的增加的責任就是跳和睡覺。

那麼什麼是透明和半透明呢?

透明的裝飾模式:

理想的裝飾模式開頭也提到了:以對客戶透明的方式動态地給一個對象附加上更多的責任。

這裡的對客戶透明實際上就是面向接口程式設計

Animal sleep= new Sleep(new Jump(new Dog()));      

還是用這個例子來說明,我們定義的是Animal,是一個接口,而不是他正在的實作Sleep類。也就是說 裝飾模式對用戶端的透明性要求程式不要聲明一個ConcreteComponent類型的變量,而應當聲明一個Component類型的變量。是以我們應該這樣寫

Animal dog = new Dog();
Animal jump = new Jump(new Dog());      

而不應該這樣寫

Dog dog = new Dog();
Jump jump = new Jump(new Dog());      

半透明的裝飾模式:

然而,純粹的裝飾模式很難找到。裝飾模式的用意是在不改變接口的前提下,增強所考慮的類的性能。在增強性能的時候,往往需要建立新的公開的方法。就好比我們需要的不僅僅是有行為能力的動物,還需要能思考的動物時,我們定義了一個Thought類,提供了思考的功能。那麼需要使用這個think()方法的時候,就不能通過聲明Animal接口來獲得這個功能,而是聲明Thought的引用。

//半透明的裝飾模式
        Thought thought = new Thought(new Dog());
        thought.think();
        thought.behavior();      

裝飾模式的優點

  (1)裝飾模式與繼承關系的目的都是要擴充對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。裝飾模式允許系統動态決定“貼上”一個需要的“裝飾”,或者除掉一個不需要的“裝飾”。繼承關系則不同,繼承關系是靜态的,它在系統運作前就決定了。

  (2)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。

裝飾模式的缺點

  由于使用裝飾模式,可以比使用繼承關系需要較少數目的類。使用較少的類,當然使設計比較易于進行。但是,在另一方面,使用裝飾模式會産生比使用繼承關系更多的對象。更多的對象會使得查錯變得困難,特别是這些對象看上去都很相像。

繼續閱讀