跳至主要內容

Decorator

StructuralGang Of FourExtensibility大约 3 分钟

或称

包装器

目的

动态的为对象附加额外的职责。装饰器为子类提供了灵活的替代方案,以扩展功能。

解释

真实世界例子

附近的山丘上住着一个愤怒的巨魔。通常它是徒手的,但有时它有武器。为了武装巨魔不必创建新的巨魔,而是用合适的武器动态的装饰它。

通俗的说

装饰者模式让你可以在运行时通过把对象包装进一个装饰类对象中来动态的改变一个对象的行为。

维基百科说

在面向对象的编程中,装饰器模式是一种设计模式,它允许将行为静态或动态地添加到单个对象中,而不会影响同一类中其他对象的行为。装饰器模式通常对于遵守单一责任原则很有用,因为它允许将功能划分到具有唯一关注领域的类之间。

程序示例

以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。

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

@Slf4j
public class SimpleTroll implements Troll {

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

下面我们想为巨魔添加球棒。我们可以用装饰者来动态的实现。

@Slf4j
public class ClubbedTroll implements Troll {

  private final 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
var 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
var 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!

类图

alt text
Decorator pattern class diagram

适用性

使用装饰者

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

教程

Java世界的例子

鸣谢