設(shè)計(jì)模式3:裝飾模式

裝飾模式(Decorator Pattern)能動態(tài)附加對象的功能,裝飾器提供了比繼承更為靈活的擴(kuò)展方案。
這個(gè)模式是繼承的一種代替方案。
一般而言,這個(gè)模式的底層是一個(gè)接口或者是抽象類。然后還需要裝飾類來擴(kuò)展該接口或者繼承抽象類,并進(jìn)行“聚合”操作。也就是說,裝飾類是在原有的功能上附加額外的功能。
還是來看代碼吧:

Troll接口,意思是怪物?巨魔?有三個(gè)函數(shù)。

/**
 * 
 * Interface for trolls
 *
 */
public interface Troll {

  void attack();

  int getAttackPower();

  void fleeBattle();

}

然后SimpleTroll類,使用Troll接口。

/**
 * 
 * SimpleTroll implements {@link Troll} interface directly.
 *
 */
public class SimpleTroll implements Troll {

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

  @Override
  public void attack() {
    LOGGER.info("The troll tries to grab you!");
  }

  @Override
  public int getAttackPower() {
    return 10;
  }

  @Override
  public void fleeBattle() {
    LOGGER.info("The troll shrieks in horror and runs away!");
  }
}

裝飾類TrollDecorator,可以看到,它不僅是使用了Troll接口,自己還另外帶一個(gè),并把接口函數(shù)全都委托給另帶的那個(gè)。

/**
 * TrollDecorator is a decorator for {@link Troll} objects. The calls to the {@link Troll} interface
 * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Troll}
 * object.
 *
 */
public class TrollDecorator implements Troll {

  private Troll decorated;

  public TrollDecorator(Troll decorated) {
    this.decorated = decorated;
  }

  @Override
  public void attack() {
    decorated.attack();
  }

  @Override
  public int getAttackPower() {
    return decorated.getAttackPower();
  }

  @Override
  public void fleeBattle() {
    decorated.fleeBattle();
  }
}

一個(gè)具體的裝飾實(shí)現(xiàn),繼承裝飾類,調(diào)用超類的基礎(chǔ)上再自己加入一些東西,而超類的實(shí)現(xiàn)也就是外帶的Troll接口實(shí)現(xiàn),這樣就在原有Troll之外增加了功能。

/**
 * Decorator that adds a club for the troll
 */
public class ClubbedTroll extends TrollDecorator {

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

  public ClubbedTroll(Troll decorated) {
    super(decorated);
  }

  @Override
  public void attack() {
    super.attack();
    LOGGER.info("The troll swings at you with a club!");
  }

  @Override
  public int getAttackPower() {
    return super.getAttackPower() + 10;
  }
}

你也許會問:這不還是繼承嗎?確實(shí)用到了繼承,但和單純使用繼承來擴(kuò)展功能還是有很大區(qū)別的。區(qū)別是什么呢?就是運(yùn)行時(shí)可以改變類的行為。

public static void main(String[] args) {

    // simple troll
    LOGGER.info("A simple looking troll approaches.");
    Troll troll = new SimpleTroll();
    troll.attack();
    troll.fleeBattle();
    LOGGER.info("Simple troll power {}.\n", troll.getAttackPower());

    // change the behavior of the simple troll by adding a decorator
    LOGGER.info("A troll with huge club surprises you.");
    Troll clubbed = new ClubbedTroll(troll);
    clubbed.attack();
    clubbed.fleeBattle();
    LOGGER.info("Clubbed troll power {}.\n", clubbed.getAttackPower());
  }
}

SimpleTroll就是普通的一個(gè)Troll,給它套上ClubbedTroll裝飾,馬上就有了ClubbedTroll的功能。以此類推,還可以加別的裝飾。這又是和繼承的另一個(gè)重要的區(qū)別:自由組合。
N個(gè)裝飾者總共可以產(chǎn)生2^N個(gè)不同類,如果一個(gè)個(gè)繼承的話……
當(dāng)然,由于裝飾者的特性,最好額外功能不要求特定的順序,也就是說額外功能之間互不影響為最佳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容