装饰器模式主要用于对原有的类的某些方法进行增强,而不需要改动原有类,使得可以灵活的扩展。
UML图如下
现假设有一辆玩具车,本身可以跑,但是速度不快,我们可以给他装个马达让他跑的更快。
首先,先把玩具抽象出来。玩具车这一类可以抽象为可移动的玩具,他们可以跑,有一定的速度。
// 可移动的玩具
public interface MovableToy {
double speed();
void run();
}
然后创建个玩具车实现这个接口
public class ToyCar implements MovableToy{
private double speed = 0.5;
@Override
public void run(){
System.out.println("can run with speed " + speed() + "m/s");
}
@Override
public double speed() {
return speed;
}
}
但是此时玩具车的速度是一定的,无法改变。那么想要在不改动当前类的前提下给他提速,可以给他装饰上一个马达,把他的速度变为原来的两倍。
// 马达装饰器
public class MotorDecorator implements MovableToy{
private MovableToy movableToy;
public MotorDecorator(MovableToy movableToy) {
this.movableToy = movableToy;
}
@Override
public void run() {
// can do something before run
System.out.println("can run with speed " + speed() + "s/m");
}
@Override
public double speed() {
return movableToy.speed() * 2;
}
}
马达装饰器需要一个MovableToy类型,所以无论是玩具车还是玩具飞机,都可以装饰上。同时,他自身也是Movable类型,所以他也可以用于装饰,即可以装饰多个马达。
测试一下
public class Main {
public static void main(String[] args) {
MotorDecorator deco = new MotorDecorator(new ToyCar());
MotorDecorator doubleDeco = new MotorDecorator(deco);
doubleDeco.run();
}
}
装饰器模式在JAVA里边最典型的应用就是IO流。例如,我们经常能看到这种写法
BufferedInputStream buffered = new BufferedInputStream(new FileInputStream(new File("filepath")));
这就是将FileInputStream进行了一次装饰,原来FileInputStream只能读取字节,而我们经常需要读取文件的内容,字节的形式很不方便,所以装饰成BufferedInputStream之后就可以读取文件里的字符了。