1、装饰者模式
装饰者模式是指在无需改变原有类及类的继承关系的情况下,动态扩建一个类的功能。通过装饰者来包裹真实的对象,并动态地向对象添加或者撤销功能。动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)。
- Component:抽象组件,定义业务需要实现的抽象方法
- ConcreteComponent:具体组件,继承(或实现)Component,定义主体对象
- Decorator:装饰者(可以为具体实现类或抽象类),实现Component接口并聚合其对象,用于给具体组件增加或减少功能
- ConcreteDecorator:具体装饰者(具体实现类),抽象类的子类,负责向组件中装饰(扩充)新的职责
2、Demo
举一个我们日常生活中的例子,我们去买饮料 =》奶茶,奶茶一开始只有原味奶茶,往奶茶里添加各种配料如珍珠、波霸、红豆等,价格均发生改变。在程序中,我们可以通过继承来实现,但顾客的需求是同时加好几种配料,那我们的继承类就得好几十个,这样的做法明显是不合理的。但是通过装饰者模式,我们就可以轻松实现:把饮料定义为抽象类(或接口),原味奶茶为饮料的具体实现类,再添加一个装饰器装饰原味奶茶的描述和价格,然后把珍珠、红豆等配料作为具体的装饰器实现类,且所有的装饰器都聚合了一个Drink对象。
- Component
package com.lin.decorator;
public abstract class Drink {
public abstract String desc();
public abstract int price();
}
- ConcreteComponent
package com.lin.decorator;
public class YuanWeiMilkTea extends Drink {
@Override
public String desc() {
return "原味奶茶";
}
@Override
public int price() {
return 10;
}
}
- Decorator
package com.lin.decorator;
public class MilkTea extends Drink {
private Drink drink;
public MilkTea(Drink drink) {
this.drink = drink;
}
@Override
public String desc() {
return drink.desc();
}
@Override
public int price() {
return drink.price();
}
}
- ConcreteDecorator
package com.lin.decorator;
public class ZenZhuMilkTea extends MilkTea {
public ZenZhuMilkTea(Drink drink) {
super(drink);
}
@Override
public String desc() {
return super.desc() + " + 珍珠";
}
@Override
public int price() {
return super.price() + 2;
}
}
package com.lin.decorator;
public class BoBaMilkTea extends MilkTea {
public BoBaMilkTea(Drink drink) {
super(drink);
}
@Override
public String desc() {
return super.desc() + " + 波霸";
}
@Override
public int price() {
return super.price() + 3;
}
}
package com.lin.decorator;
public class RedBeanMilkTea extends MilkTea {
public RedBeanMilkTea(Drink drink) {
super(drink);
}
@Override
public String desc() {
return super.desc() + " + 红豆";
}
@Override
public int price() {
return super.price() + 10;
}
}
- 测试
public static void main(String[] args) {
//原味奶茶
Drink tea = new YuanWeiMilkTea();
MilkTea milkTea = new MilkTea(tea);
System.out.println(milkTea.desc() + ":" + milkTea.price());
//加珍珠
milkTea = new ZenZhuMilkTea(milkTea);
System.out.println(milkTea.desc() + ":" + milkTea.price());
//加波霸
milkTea = new BoBaMilkTea(milkTea);
System.out.println(milkTea.desc() + ":" + milkTea.price());
//加红豆
milkTea = new RedBeanMilkTea(milkTea);
System.out.println(milkTea.desc() + ":" + milkTea.price());
}
原味奶茶:10
原味奶茶 + 珍珠:12
原味奶茶 + 珍珠 + 波霸:15
原味奶茶 + 珍珠 + 波霸 + 红豆:25
3、装饰器模式在Java中的应用
3.1、节点流和处理流
我们都知道Java中IO流可以分为节点流和处理流,看节点流和处理流的定义是不是很像上面的在奶茶上添加配料
- 节点流:直接从数据源或目的地读写数据
- 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更强大的读写功能
3.2、UML
- InputStream:类似上面的Drink,是一个抽象类
- FileInputStream:类似上面的YuanWeiMilk,是Drink的实现类
- FilterInputStream:类似上面Decorator,是装饰器
- BufferedInputStream、DataInputStream…:类似上面Decorator的实现类,就是Drink的各种配料