裝飾器模式(Decorator)

jdon發表於2019-06-19

目的
動態地將附加職責附加到物件上。裝飾器為擴充套件功能提供了一種靈活的子類替代方案。

說明
附近的山上有一個憤怒的巨魔。通常它是徒手但有時它有武器。為了武裝巨魔,沒有必要創造一個新的巨魔,可用合適的武器動態裝飾它。

簡而言之
Decorator模式允許您透過將物件包裝在裝飾器類的物件中來動態更改物件在執行時的行為。

維基百科說
物件導向的程式設計中,裝飾器模式是一種設計模式,它允許將行為靜態或動態地新增到單個物件,而不會影響同一類中其他物件的行為。裝飾器模式通常用於遵守單一責任原則,因為它允許在具有特定關注領域的類之間劃分功能。

原始碼示例
讓我們來看看巨魔的例子吧。首先,我們有一個簡單的巨魔實現troll介面

public interface Troll {
  void attack();
  int getAttackPower();
  void fleeBattle();
}

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!");
  }
}


接下來我們想為巨魔新增俱樂部。我們可以使用裝飾器動態地完成它

public class ClubbedTroll implements Troll {

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

  private Troll decorated;

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

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

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

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


這是行動中的巨魔

// simple troll
Troll troll = new SimpleTroll();
troll.attack(); // The troll tries to grab you!
troll.fleeBattle(); // The troll shrieks in horror and runs away!

// change the behavior of the simple troll by adding a decorator
Troll clubbedTroll = new ClubbedTroll(troll);
clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you with a club!
clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away!


適用場景

  • 動態且透明地向各個物件新增職責,即不影響其他物件
  • 對於可以撤回的職責
  • 透過子類擴充套件不可行時。有時可能會有大量獨立擴充套件,並會產生大量子類以支援每種組合。或者類定義可能被隱藏,或者無法用於子類化。

相關文章