裝飾模式(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個不同類,如果一個個繼承的話……
當然,由于裝飾者的特性,最好額外功能不要求特定的順序,也就是說額外功能之間互不影響為最佳。