設計模式--裝飾者模式

  1. 給類或對象添加行爲的方式

    1. 使用繼承,這是一個靜態的方式,在編譯的時候就已經決定了子類的行爲,不便於空值增加子類行爲的方式和時機。
    2. 適用關聯,將一個對象嵌入到另一個對象中,這是一種動態的方式,可以在應用程序中動態的控制。
  2. 裝飾者模式在不改變原類文件和繼承(與適配器模式的小的區別)的情況下,動態的擴展一個對象的功能。

  3. 裝飾者模式通過創建一個包裝對象(裝飾對象)包裹真實的對象。

  4. 適配器模式與裝飾者模式的區別

    1. 適配器模式是講一個接口轉變成另一個接口(兼容性),通過改變原有的接口達到重複使用的目的。
    2. 適配器模式是在不改變原有接口的情況下,增強原有對象的功能;或者在不改變原有對象的處理方法而提升性能(動態的添加行爲)。
  5. 裝飾者模式的UML圖

    在這裏插入圖片描述

  6. component抽象構建(最終想要得到的對象),concreteComponent具體的對象,decorator抽象裝飾類,concreteDecorator具體裝飾類,起到該Conponent添加職責的功能。

  7. 裝飾者模式的代碼實現過程

    1. 創建一個抽象原型接口

      /**
       * Component對象(抽象對象類),手類抓餅接口,用來被裝飾
       */
      public interface Cake {
      
          String nameDetail();
      
          Double price();
      
      }
      
      
    2. 創建一個具體的原型類

      /**
       * 基礎對象類(原型對象),原味手抓餅
       */
      public class CakeImpl implements Cake {
      
          @Override
          public String nameDetail() {
              return "手抓餅";
          }
      
          @Override
          public Double price() {
              return 5.00;
          }
      
      }
      
    3. 創建原型類的裝飾者抽象類

      /**
       * 裝飾者抽象類,手抓餅的裝飾類,第一次使用了構造方法
       */
      public class CakeDecorator implements Cake {
      
          private Cake cake;
      
          /**
           * 構造函數是爲了能堆上一步的對象進行處理
           * @param cake
           */
          public CakeDecorator(Cake cake) {
              this.cake = cake;
          }
      
          @Override
          public String nameDetail() {
              return cake.nameDetail();
          }
      
          @Override
          public Double price() {
              return cake.price();
          }
      
      }
      
    4. 創建三個原型抽象類的具體裝飾類

      /**
       * 具體的裝飾者類,雞蛋手抓餅
       *  1. 繼承了父類的構造方法
       *  2. 實現了具體的裝飾裝飾內容
       */
      public class AggCakeDecorator extends CakeDecorator {
      
          public AggCakeDecorator(Cake cake) {
              super(cake);
          }
      
          /**
           * 實現具體的裝飾內容
           * @return
           */
          @Override
          public String nameDetail() {
              return "雞蛋"+super.nameDetail();
          }
      
          @Override
          public Double price() {
              return super.price()+1.5;
          }
      }
      
      /**
       * 具體的裝飾者類,牛肉手抓餅
       *  1. 繼承了父類的構造方法
       *  2. 實現了具體的裝飾裝飾內容
       */
      public class MeatCakeDecorator extends CakeDecorator {
      
          public MeatCakeDecorator(Cake cake) {
              super(cake);
          }
      
          @Override
          public String nameDetail() {
              return "牛肉"+super.nameDetail();
          }
      
          @Override
          public Double price() {
              return super.price()+2;
          }
      
      }
      
      /**
       * 具體的裝飾者類,奶油手抓餅
       *  1. 繼承了父類的構造方法
       *  2. 實現了具體的裝飾裝飾內容
       */
      public class MilkCakeDecorator extends CakeDecorator {
      
          public MilkCakeDecorator(Cake cake) {
              super(cake);
          }
      
          @Override
          public String nameDetail() {
              return "奶油"+super.nameDetail();
          }
      
          @Override
          public Double price() {
              return super.price()+3;
          }
      
      }
      
    5. 編寫測試類

      public class Test {
          public static void main(String[] args) {
              Cake cake = new CakeImpl();
              System.out.println("name: " + cake.nameDetail() +", price: " + cake.price());
              System.out.println("--------------------");
      
              Cake cake1 = new AggCakeDecorator(cake);
              System.out.println("name: " + cake1.nameDetail() +", price: " + cake1.price());
      
              System.out.println("--------------------");
              Cake cake2 = new MeatCakeDecorator(cake1);
              System.out.println("name: " + cake2.nameDetail() +", price: " + cake2.price());
      
              System.out.println("--------------------");
              /**
               * 標識了製作順序與流程,在生產中要進行流水線製作程序的時候,
               有可能會嚴格的把控制作流程
               * 裝飾者模式不僅完成了操作細節的裝飾,還能堆操作的流程提供很好的調用方式
               */
              Cake cake3 = new MilkCakeDecorator(cake2);
              System.out.println("name: " + cake3.nameDetail() +", price: " + cake3.price());
          }
      }
      
  8. 裝飾者模式的優點

    1. 裝飾者模式可以提供比繼承更多的靈活性
    2. 可以通過一種動態的方式來擴展一個對象的功能,在運行時選擇不同的裝飾器,實現不同的行爲
    3. 通過使用不同具體的裝飾器,以及這些裝飾器的排列組合,可以創造出很多不同行爲的組合。實現多個具體的裝飾類裝飾同一個對象,得到功能更爲強大的對象。
    4. 具體的構造類與具體的裝飾類可以獨立變化,用戶可以根據需要增加新的具體構建類和具體裝飾類;使用的時候還可以進行組合,原有的代碼無需改變,符合"開閉原則"
  9. 裝飾者模式的缺點

    1. 會產生很多小對象,增加系統的複雜度
    2. 這種比繼承更加領過機動的特性,同時也意味着裝飾模式比繼承更加容易出錯,排錯也很困難,對於多次裝飾的對象,調試的時候尋找錯誤需要逐級排查,比較繁瑣
  10. 裝飾者模式的使用場景

    1. 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責
    2. 需要動態的給一個對象增加功能,這些功能也可以動態的撤銷,當不能採用繼承的方式對系統進行擴展或者採用繼承不利於系統擴展和維護的時候。
  11. 裝飾者模式在JDK中的使用

    在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章