装饰器模式
在不改变原有类和继承关系的基础上,动态地拓展一个对象的功能。通过创建一个包装对象,包裹真实的对象,以完成功能的拓展。
想象一个场景,你有一辆车,它可以在陆地上跑,现在我需要一辆能在水里开的车。怎么办?继承汽车类,然后新增方法runInWater()?
好,可以。那么我现在需要一辆能飞的车。怎么办?继承汽车类,然后新增方法runInAir()?
好,可以。那么我现在需要一辆即能在水里开,又能在空中飞的车。怎么办?Java不支持多继承,难道又要去继承汽车类?还是去继承能在水里开的车,抑或是能飞的车?
然后功能继续增加,你就疯了。
在桥接模式的时候,已经疯过一次了,这里不能再疯了。
装饰模式和桥接模式的区别:
两个模式都是为了解决过多子类对象的问题,但是他们的诱因不同。
桥接模式是对象自身现有机制沿多个维度变化,是既有部分不稳定,装饰模式是为了增加新的功能。
下面开始上代码。本文示例,就是上述的多功能汽车。(本文示例参考自北京尚学堂Java教程,高淇)
先来一个汽车接口,只有一个方法move():
public interface ICar {
void move();
}
再来一个ConcreteComponent具体构建对象,这就是真实对象:
//ConcreteComponent具体构件对象(真实对象)
class Car implements ICar{
@Override
public void move() {
System.out.println("陆地上跑!");
}
}
之后就是Decorator装饰对象:
//Decorator装饰角色
class SuperCar implements ICar{
protected ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
}
@Override
public void move() {
car.move();
}
}
装饰对象实现了ICar接口,并且持有一个ICar的引用,在重写的move()函数中,实际调用的传入的ICar引用的move()方法。
接着是具体的装饰角色:
//ConcreteDecorator具体装饰角色
class FlyCar extends SuperCar{
public FlyCar(ICar car) {
super(car);
}
public void fly(){
System.out.println("天上飞");
}
@Override
public void move() {
super.move();
fly();
}
}
class WaterCar extends SuperCar{
public WaterCar(ICar car) {
super(car);
}
public void swim(){
System.out.println("水里游");
}
@Override
public void move() {
super.move();
swim();
}
}
class AICar extends SuperCar{
public AICar(ICar car) {
super(car);
}
public void autoMove(){
System.out.println("自动驾驶");
}
@Override
public void move() {
super.move();
autoMove();
}
}
最后测试一下:
public class Client {
public static void main(String[] args) {
Car car = new Car();
car.move();
System.out.println("==增加飞行功能==");
FlyCar flyCar = new FlyCar(car);
flyCar.move();
System.out.println("==增加水上功能==");
WaterCar waterCar = new WaterCar(car);
waterCar.move();
System.out.println("==全能车==");
AICar aiCar = new AICar(new FlyCar(new WaterCar(car)));
aiCar.move();
}
}
首先我们有一个具体的真实对象Car,普通的车。开起来car.move();接着我们给他增加一个飞行功能,外面装饰一层FlyCar,开起来flyCar.move();再来一个全能车,装饰100层
看下输出:
陆地上跑!
==增加飞行功能==
陆地上跑!
天上飞
==增加水上功能==
陆地上跑!
水里游
==全能车==
陆地上跑!
水里游
天上飞
自动驾驶
可以看到,随着装饰的层数增加,功能也增多了,但是没有增加多余的类。
总结:
装饰模式(Decorator)也叫包装器模式(Wrapper)
装饰模式降低系统耦合度,可以动态地增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。
优点:
-拓展对象功能,比继承灵活,不会导致类个数急剧增加
-可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
-具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构建子类和具体装饰子类
确定:
-产生很多小对象。大量小对象占据内存,一定程度上影响性能。
-装饰模式易于出错,调试排查比较麻烦。
常用场景:
IO流实现细节就是典型的装饰模式
-Component抽象构件角色:
·io流中的InputStream、OutputStream、Reader、Writer
-ConcreteComponent具体构建角色
·io流中的FileInputStream、FileOutputStream
-Decorator装饰角色:
·持有一个抽象构件的引用:io流中的FilterInputStream、FilterOutputStream
-ConcreteDecorator具体装饰角色:
·负责给构建对象增加新的责任。io流中的BufferedOutputStream、BufferedInputStream等。