装饰模式(Decorator)最常见的就是JDK中的关于I/O流的处理。
DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
装饰模式的类图如下:
首先是抽象的接口Component
public interface Component{ void sampleOperation(); }
下面是装饰角色的代码Decorator,继承了Component接口,调用的方法还是父类的方法,但并不是单纯的调用父类方法,而是在功能上有所增强。
public class Decorator implements Component{ private Component component; public Decorator(Component component){ this.component = component; } public Decorator() {
//write code here } public void sampleOperation(){ component.sampleOperation(); } }
具体装饰角色的源代码如下,
public class ConcreteDecorator extends Decorator{ public void sampleOperation(){ super.sampleOperation(); } }
一个典型的装饰模式的创建过程如下:
new Decorator1(new Decorator2(new Decorator(new ConcreteComponent())))
Decorator1持有一个Decorator2对象的引用,后者持有一个Decorator3的引用,Decorator3持有的是ConcreteDecorator的引用。
齐天大圣的例子中,齐天大圣角色是抽象接口Component,ConcreteComponent是大圣本尊,就是本人。大圣化身是Decorator角色,而花,鸟,鱼,虫的角色是ConcreteDecorator。
齐天大圣的示例代码:
public interface MonkeyKing{ public void laugh(); }
大圣本尊的实例代码:
public class MonkeySelf implements MonkeyKing{ public MonkeySelf (){ } public void laugh(){ System.out.println("laugh like a monkey!"); } }
大圣化身的实例代码:
public class MokeyAvactor implements MonkeyKing{ private MonkeyKing mk; public MokeyAvactor(MonkeyKing mk){ this.mk = mk; } public void laugh(){ mk.laugh(); } }
大圣变成的鱼的实例代码:
public class FishAvator extends MokeyAvactor{ public FishAvator(MonkeyKing mk){ super(mk); } public void laugh(){ super.laugh(); } public void swim(){ System.out.println("FishAvator is swimming!"); } }
大圣变成的鸟的实例代码:
public class BirdAvator extends MokeyAvactor{ public BirdAvator(MonkeyKing mk){ super(mk); } public void laugh(){ super.laugh(); } public void fly(){ System.out.println("BirdAvator is flying!"); } }
测试各种变身的类的代码:
public class AvatorTest { public static void main(String [] args){ MonkeyKing mk = new MonkeySelf(); MonkeyKing fish = new FishAvator(mk); fish.laugh(); MonkeyKing bird = new BirdAvator(fish); bird.laugh(); } }
测试的结果为:
laugh like a monkey!
laugh like a monkey!
由大圣本尊化身为的鸟和鱼的laugh调用的还是大圣本尊的laugh。
MonkeyKing fish = new FishAvator(mk);符合面向接口编程的原则,但是如果需要用Fish的swim方法,这种写法就不行了,只能写成:
FishAvator fish = new FishAvator(mk);这种被称为半透明的装饰模式,或者称为退化的装饰模式。
装饰模式提供了比继承更为灵活的功能,通过不同的组合,对象将拥有不同的属性。
回到最开始的I/O流中的代码:
DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
查看代码,DataInputStream中的read方法都是调用传入的InputStream的read方法,对应上面就是调用的BufferedInputStream的read方法。
InputStream可以看做抽象接口,BufferedInputStream可以看做ConcreteComponent,DataInputStream可以看做ConcreteDecorator,就可以和上面装饰模式的类图对应上了。
实际中使用的装饰模式要比刚开始的类图结构简单些,下面是简化了的装饰模式的类图。
省略Component的情况:
只有一个ConcreteDecorator,则Decorator是可以省略的: