装饰者模式
定义:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰者模式角色介绍
- Componet:抽象组件角色,定义公共责任接口。
- ConcreteComponet:具体组件角色,定义一个将要接收附加责任的类。
- Decorator:抽象装饰角色,内部持有Componet对象实例,并在实现Componet的方法里使用Componet对象实例的责任方法。
- ConcreteDecorator:具体装饰角色,负责给构件对象添加上附加的责任。
《Effective Java》中提到组合优于继承。尽量使用组合而不是继承。为什么组合优于继承,这里不多说,装饰者模式就是利用组合的方式解决继承的缺点。装饰者模式是为了装饰组件类型,装饰有很多方式,例如一杯咖啡,每个人的口味都不一样,有的人喜欢加糖不加奶,有的人喜欢加糖又加奶,还有的人喜欢加冰。没认识装饰者模式之前,每次改动都需要花大量的精力,一不小心就多了几个BUG,得不偿失。这时就应该考虑使用装饰者模式了。
代码示例
饮料组件类
public interface Drink {
void make();//定义责任方法
}
具体饮料(咖啡)
public class Coffee implements Drink{
public void make() {
System.out.print("咖啡");
}
}
抽象装饰者(添加物)
public abstract class Addition implements Drink{
protected Drink drink;
public Addition(Drink drink){
this.drink = drink;
}
public void make() {
drink.make();
}
}
具体装饰者(奶、糖、冰)
public class Milk extends Addition{
public Milk(Drink drink){
super(drink);
}
public void make() {
System.out.print("加奶");
super.make();
}
}
public class Sugar extends Addition{
public Sugar(Drink drink) {
super(drink);
}
public void make() {
System.out.print("加糖");
super.make();
}
}
public class Ice extends Addition {
public Ice(Drink drink) {
super(drink);
}
public void make() {
System.out.print("加冰");
super.make();
}
}
客户端
Drink coffee = new Coffee();
Addition addition = new Ice(new Milk(new Sugar(coffee)));
addition.make();
输出为:加冰加奶加糖咖啡
需要加多点冰就再套一个冰装饰者,不需要可以去掉,没有顺序要求。
Addition addition = new Ice(new Milk(new Sugar(new Ice(coffee))));//加多一倍冰
如果新增一个添加物,只要派生新的装饰者就可以了,不用改动原有的类,连判断逻辑都不需要。装饰者模式作用也是非常明显的,扩展性非常强,符合开闭原则,属于结构型模式。JavaIO类就有装饰者模式的实例。不足之处望指教。