装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
设计原则:
封装变化
多用组合,少用继承
针对接口编程,不针对实现
编程
为交互对象之间的松耦合设计而努力
对扩展开放,对修改关闭。
一旦你熟悉了装饰的技巧,你将能够在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。
如果我们通过继承来描述一杯奶茶,那么拥有不同属性的奶茶都是一个独立的类,奶茶可以加不同的料,甚至可以有无数种搭配,这样一来为自己制造了一个维护恶梦。如果奶茶的价钱上扬,怎么办?新增一种焦糖调料风味时,怎么办?
造成这种维护上的困难,违反了以上的设计原则。
所以,在这里要采用不一样的做法:我们要以饮料为主体,然后在运行时以调料来“装饰”(decorate)饮料。
1、拿一个原味奶茶(MilkTea)对象
2、以珍珠(Pearl)对象装饰它
3 、以椰果(Coconut)对象装饰它
4 、调用cost()方法,并依赖委托(delegate)将调料的价钱加上去。
但是如何“装饰”一个对象,而“委托”又要如何与此搭配使用呢?把装饰者对象当成“包装者”。让我们看看这是如何工作的……
顾客要一杯珍珠奶茶,创建MilkTea多态对象,顾客想要珍珠(Pearl),所以建立一个Pearl对象,并用它将MilkTea对象包起来,这时的价钱是原味奶茶加珍珠,通过调用最外圈装饰者的cost()就可以办得到。cost()会先委托它装饰的对象(也就是Pearl)计算出价钱
饮料类、奶茶类
public abstract class Beverage {
String detail = "";
public String getDetail() {
return detail;
}
public abstract double cost();
}
public class MilkTea extends Beverage {
public String getDetail() {
return "原味奶茶";
}
@Override
public double cost() {
return 8.0;
}
}
抽象装饰类
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
具体装饰类
public class Pearl extends CondimentDecorator {
private Beverage beverage;
public Pearl(Beverage beverage) {
this.beverage = beverage;
}
public double cost() {
return beverage.cost() + 2;
}
@Override
public String getDetail() {
return "珍珠" + beverage.getDetail();
}
}
测试
public class Test {
public static void main(String[] args) {
Beverage milktea = new MilkTea();
milktea = new Pearl(milktea);
System.out.println(milktea.getDetail()+"花费"+milktea.cost());
}
}
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。