装饰器模式(Decorator)

19-06-19 jdon
              

目的

动态地将附加职责附加到对象上。装饰器为扩展功能提供了一种灵活的子类替代方案。

说明

附近的山上有一个愤怒的巨魔。通常它是徒手但有时它有武器。为了武装巨魔,没有必要创造一个新的巨魔,可用合适的武器动态装饰它。

简而言之

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!

适用场景

  • 动态且透明地向各个对象添加职责,即不影响其他对象
  • 对于可以撤回的职责
  • 通过子类扩展不可行时。有时可能会有大量独立扩展,并会产生大量子类以支持每种组合。或者类定义可能被隐藏,或者无法用于子类化。