天天看點

淺學設計模式之裝飾模式 (2/23)

1、裝飾模式的概念

裝飾模式就是動态地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更加靈活。

對于人來說,衣服、鞋子、領帶、襪子等都是裝飾,裝飾模式就是給光着身子的人穿上各種衣服褲子。

對于程式對象來說,每一個功能都是裝飾,給一個類增加功能,就是給這個類進行裝飾。

2、裝飾模式的UML圖及對應代碼

淺學設計模式之裝飾模式 (2/23)

Compoent是一個對象接口,可以給這些對象動态地添加職責:

class interface Component{
    void Operation();
}      

ConcreteComponent類,定義了一個具體的對象,也可以給這個對象添加一些職責:

class ConcreteComponent implement Component{
   
   @Override
   public void Operation(){
       //做一些具體的操作
   } 
}      

Decorator 是裝飾抽象類,繼承了Component接口,從外類來擴充Component類的功能,但是對于Component來說,是無需要知道Decorator的存在的。

public class Decorator implements Component{
    protected Component component;
    
    //設定Component
    public SetComponent(Component component){
        this.component = component;
    }

    //重寫Operation(),實際執行的是Component的Operation()
    @Override
    public void Operation() {
        if(component != null){
           component.Operation();
        }
    }   
}      

ConcreteDecorator 是具體的裝飾對象,起到給Component添加職責的功能

我們來實作一下A和B

public class ConcreteDecoratorA extends Decorator {
    
    //本類特有的功能,以差別B
    private String addedState;
    
    @Override
    public void Operation() {
      // 首先運作原Component的Operation()
   super.sampleOperation();
     // 再執行本類的功能,如addState相當于對原Component進行了裝飾
     addState = "New State";
     //具體裝飾對象A的操作。
    }
}

public class ConcreteDecoratorB extends Decorator {
    
    //本類特有的方法,以差別A
    public AddBehavior() {
    }
    
    @Override
    public void Operation() {
      // 首先運作原Component的Operation()
   super.sampleOperation();
     // 再運作自己的功能
     AddBehavior();
     ....
    }
}      

最後用戶端代碼點睛之筆:

main(){
            ConcreteComponent c = new ConcreteComponent();
            ConcreteDecoratorA d1 = new  ConcreteDecoratorA();
            ConcreteDecoratorB d2 = new  ConcreteDecoratorB();
            
            //裝飾的方法是:
            //首先用 ConcreteComponent執行個體化c
            //然後用 ConcreteDecoratorA的執行個體化對象d1來包裝c
            //再用ConcreteDecoratorB的對象d2來包裝d1
            //最後執行d2的Operation
            d1.setComponent(c);
            d2.setComponent(d1);
            d2.Operation();
            ...
       }      
  • 裝飾模式就是利用SetComponent來對對象進行包裝的。

    這樣每個裝飾對象的實作就和如何使用這個對象分離開了,每個裝飾對象值關心自己的功能,不需要關心如何被添加到對象鍊當中。

注:不一定要去構造Component類,要善于變通,假如隻有一個ConcreteComponent(我們隻修飾一個“人”),那麼久沒有必要些Component類,同時,Decorator就是ConcreteComponent類的子類,如果ConcreteDecorator隻有一個(“衣服”隻有一件),那麼也沒有必要構造Decorator,直接讓唯一的ConcreteDecorator來繼承ConcreteComponent就行啦。

3、經典場景—穿衣服

在這個場景下,我們給一個人穿各種衣服,包括褲子、襪子、鞋子、衣服。

在之前的UML來說,ConcreteComponent可以說是代表着具體的一類人,而這個問題讓我們針對這個人,是以我們可以不用構造Component類,或者說 “人”這個類就是Component類。而Decorator很自然就是“服裝類”,其子類就是各種衣服,那麼我們可以畫出下面的UML圖:

淺學設計模式之裝飾模式 (2/23)

接着按圖來寫代碼:

首先是Person類

class Person{
     public Person(){
     }
     private String name;
     public Person(String name){
     this.name = name;
     }
     public abstract void show(){
     System.out.plintln("穿衣服的rikka");
     }
}      

接着是服飾類Finery:

class Finery extends Person{
     protected Person component;
     //打扮
     public void Decorate(Person component){
     this.component = component;
     }
     
     @Override
     public void show(){
     if(component != null){
        component.show();
       }
     }
}      

接下來就是具體服飾類ConcreteDecorator

class GoldLianzi extends Finery{
     @Override
     public void show(){
       System.out.prinlin("大金鍊子");
       super.show();
     }
}
class Sunglasses extends Finery{
     @Override
     public void show(){
       System.out.prinlin("墨鏡");
       super.show();
     }
}      

最後的用戶端代碼:

main(){
     Person rikka = new Person("Rikka");
     
     System.out.println("裝扮\n");
     
     Sunglasses sunglasses = new Sunglasses();
     GoldLianzi gold = new GoldLianzi();
     Cigarette cigarette = new Cigarette();
     ThugLife thuglife = new ThugLife();
       
     sunglasses.Decorate(rikka);
     gold.Decorate(sunglasses);
     cigarette.Decorate(gold);
     thuglife.Decorate(cigarette);
     thuglife.show();
}      

結果顯示:

裝扮
ThugLife帽子 香煙 大金鍊子 墨鏡 穿衣服的rikka      

這樣,我們就為一個什麼都沒有穿的人,穿上了各種衣服啦!

同理就是給類加功能。

總結

學了這麼多,其實裝飾模式是為已有功能動态地添加更多功能的一種設計模式。

問題:在以往,在系統功能需要更新的時候,是向舊類添加新的代碼,這些新的代碼通常裝飾了原有類的核心職責或主要行為,但這種做法的問題就在于:它們在主類中加入了新的字段,新的方法和新的邏輯,進而增加了主類的複雜度。