装饰模式(Decorator Pattern)能动态附加对象的功能,装饰器提供了比继承更为灵活的扩展方案。
这个模式是继承的一种代替方案。
一般而言,这个模式的底层是一个接口或者是抽象类。然后还需要装饰类来扩展该接口或者继承抽象类,并进行“聚合”操作。也就是说,装饰类是在原有的功能上附加额外的功能。
还是来看代码吧:
Troll接口,意思是怪物?巨魔?有三个函数。
/**
*
* 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接口,自己还另外带一个,并把接口函数全都委托给另带的那个。
/**
* 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();
}
}
一个具体的装饰实现,继承装饰类,调用超类的基础上再自己加入一些东西,而超类的实现也就是外带的Troll接口实现,这样就在原有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;
}
}
你也许会问:这不还是继承吗?确实用到了继承,但和单纯使用继承来扩展功能还是有很大区别的。区别是什么呢?就是运行时可以改变类的行为。
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就是普通的一个Troll,给它套上ClubbedTroll装饰,马上就有了ClubbedTroll的功能。以此类推,还可以加别的装饰。这又是和继承的另一个重要的区别:自由组合。
N个装饰者总共可以产生2^N个不同类,如果一个个继承的话……
当然,由于装饰者的特性,最好额外功能不要求特定的顺序,也就是说额外功能之间互不影响为最佳。