設計模式學習筆記(3)裝飾器

本文實例代碼:github.com/JamesZBL/ja…java

裝飾器(Decorator)模式用於動態地給一個對象添加一些額外的職責。 就增長功能來講, Decorator模式相比生成子類更爲靈活。裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關係的一個替代方案。git

純粹的裝飾模式很難找到,大多數的裝飾模式的實現都是「半透明」的,而不是徹底透明的。換言之,容許裝飾模式改變接口,增長新的方法。半透明的裝飾模式是介於裝飾模式和適配器模式之間的。適配器模式的用意是改變所考慮的類的接口,也能夠經過改寫一個或幾個方法,或增長新的方法來加強或改變所考慮的類的功能。 大多數的裝飾模式其實是半透明的裝飾模式,這樣的裝飾模式也稱作半裝飾、半適配器模式。github

適用場景

如下狀況使用Decorator模式bash

  • 在不影響其餘對象的狀況下, 以動態、 透明的方式給單個對象添加職責。ide

  • 處理那些能夠撤消的職責。this

  • 當不能採用生成子類的方法進行擴充時。 一種狀況是, 可能有大量獨立的擴展, 爲支持每一種組合將產生大量的子類, 使得子類數目呈爆炸性增加。 另外一種狀況多是由於類定義被隱藏, 或類定義不能用於生成子類。spa

模式要點

image

組成部分

  • Component:定義一個對象接口, 能夠給這些對象動態地添加職責。code

  • ConcreteComponent:定義一個對象, 能夠給這個對象添加一些職責。cdn

  • Decorator:持有一個指向 Component 對象的引用,並定義一個與 Component 接口一致的接口。對象

  • ConcreteDecorator:一貫組件添加職責。

協做原理

  • Decorator 將請求轉發給它的 Component 對象, 並有可能在轉發請求先後執行一些附加的動做。

實例分析

[站外圖片上傳中...(image-a0ad13-1526278884853)]

鐵匠和木匠同時製做一把鐵錘,第一種方案是木匠製做錘把,鐵匠製做錘頭;第二中方案是鐵匠先製做錘把再製做錘頭(假定這裏的木匠只會製做錘把)。製做過程分爲三部分:1.對材料進行初步的檢查,2.進行製造並把部件安裝起來以供後面的操做,3.完成以後再次進行檢查,確保沒有質量問題。

首先定義「操做」接口,包括先後兩次檢查以及安裝的操做。

/** * 流水線上操做行爲的接口 */

public interface Operation {

  void checkBefore();

  void join();

  void chekcAfter();

}

複製代碼

如今只由木匠製做錘把,定義一個木匠的操做類 CarpenterOperation

/** * 木匠的工做 */

public class CarpenterOperation implements Operation {

  private static final Logger LOGGER = LoggerFactory.getLogger(CarpenterOperation.class);

  @Override

  public void checkBefore() {

    LOGGER.info("檢查木材");

  }

  @Override

  public void join() {

    LOGGER.info("打造錘把");

  }

  @Override

  public void chekcAfter() {

    LOGGER.info("檢查成品錘把");

  }

}

複製代碼

因爲某些緣由,鐵匠決定本身製做錘把,如今鐵匠身兼雙職,將木匠的工做也承擔了。定義一個鐵匠操做類 HammerSmith

/** * 鐵匠 */

public class HammerSmithOperation implements Operation {

  private static final Logger LOGGER = LoggerFactory.getLogger(HammerSmithOperation.class);

  private Operation previousOperation;

  public HammerSmithOperation(Operation previousOperation) {

    this.previousOperation = previousOperation;

  }

  @Override

  public void checkBefore() {

    previousOperation.checkBefore();

    LOGGER.info("檢查鐵材");

  }

  @Override

  public void join() {

    previousOperation.join();

    LOGGER.info("打造錘頭");

  }

  @Override

  public void chekcAfter() {

    previousOperation.chekcAfter();

    LOGGER.info("檢查成品錘頭");

  }

}

複製代碼

一樣實現了「操做」的接口,鐵匠的每一個操做都包含了木匠相應的操做,至關於對木匠的操做增長了一層包裹和擴展。這種包裝就是 Decorator 模式中的裝飾。

如今分別讓木匠和鐵匠進行一系列操做

/** * Decorator */

public class Application {

  private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) {

    LOGGER.info("僅由木匠製做錘把");

    Operation carpenter = new CarpenterOperation();

    carpenter.checkBefore();

    carpenter.join();

    carpenter.chekcAfter();

    LOGGER.info("由鐵匠完成錘把以及錘頭的製做");

    Operation hammerSmith = new HammerSmithOperation(carpenter);

    hammerSmith.checkBefore();

    hammerSmith.join();

    hammerSmith.chekcAfter();

  }

}

複製代碼

輸出以下內容

僅由木匠製做錘把

    檢查木材

    打造錘把

    檢查成品錘把

    由鐵匠完成錘把以及錘頭的製做

    檢查木材

    檢查鐵材

    打造錘把

    打造錘頭

    檢查成品錘把

    檢查成品錘頭

複製代碼

效果

優勢

1. 裝飾模式和靜態繼承的機制的做用都是對現有的類增長新的功能,但裝飾模式有着比靜態繼承更靈活的組合方式。裝飾模式能夠在運行的時候決定須要增長仍是去除一種「裝飾」以及什麼「裝飾」。靜態繼承則沒有這樣的靈活性,它對類功能的擴展是在運行以前就肯定了的。

2. 得益於裝飾模式在組合上的靈活性和便利性,咱們能夠將各類裝飾類進行組合,從而較爲簡單的創造各類不一樣的行爲集合,實現多種多樣的功能。

缺點

1. 裝飾者的對象和它裝飾的對象本質上是徹底不一樣的,裝飾模式會生成許多的對象,致使區分各類對象變得困難

2. 因爲使用相同的標識,對於程序的理解和排錯過程的難度也會隨之增長

我的博客同步更新,獲取更多技術分享請關注:鄭保樂的博客

相關文章
相關標籤/搜索