简介
1.装饰者模式:动态的将新功能附加到对象上,在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(OCP)
2.这里提到的动态的将新功能附加到对象和OCP原则,在后面的应用实例上会以代码的形式体现
装饰者模式的原理
需求案例 星巴克咖啡订单项目(咖啡馆)
1.咖啡种类/单品咖啡:Espresso(意大利浓咖啡).ShortBlack,LongBlack(美式咖啡),Decaf(无因咖啡)
2.调料:Milk,Soy(豆浆),Chocolate
3.要求在拓展新的咖啡种类时.具有良好的拓展性.改动方便,维护方便
4.使用OO的来计算不同种类的咖啡的费用:客户可以点单品咖啡,也可以点单品咖啡+调料组合
解决星巴克订单项目的问题分析(解决方案1)
1.普通方法 使用单品咖啡和调料组合的排列组合很多,那么类也很多
2.Drink 是一个抽象类 表示饮料
3.des 就是对咖啡的描述 ,比如咖啡的名字
4.cost()方法就是计算费用 Drink类中会做成一个抽象方法
5.Decaf 就是单品咖啡,继承 Drink 并且实现 cost
6.Espresso && Milk 就是单品咖啡+饮料,这个组合很多
7.问题:这样设计,会有很多类,当我们增加单品咖啡或者新的调料 类的数量就会倍增 就是会出现类爆炸
解决方案2
前面分析到方案1因为 咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到 Drink类,这样就不会造成类数量过多从而提高项目的维护性
说明
milk.soy,chocolate可以设计为 boolean 表示是否添加相应的调料
方案2问题分析
1.方案2可以控制类的数量,不至于造成类爆炸
2.但是在增加或者删除调料的时候,维护性很差,维护数量很大
3.考虑到用户可以添加多份, 调料的时候,可以将hasMilk 返回一个对应的 int
4.可以考虑 ==>> 装饰者模式
类图分析和代码演示
类图分析
代码演示
public abstract class Drink {
public String des; // 描述
private float price = 0.0F;
/**
* @return the des
*/
public String getDes() {
return des;
}
/**
* @param des the des to set
*/
public void setDes(String des) {
this.des = des;
}
/**
* @return the price
*/
public float getPrice() {
return price;
}
/**
* @param price the price to set
*/
public void setPrice(float price) {
this.price = price;
}
//计算费用的抽象方法
//子类来实现
public abstract float cost();
}
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
public class Espresso extends Coffee{
public Espresso() {
setDes(" 意大利咖啡 ");
setPrice(50.0F);
}
}
public class LongBlack extends Coffee {
public LongBlack() {
setDes(" 美式咖啡 ");
setPrice(60.0F);
}
}
public class ShortBlack extends Coffee{
public ShortBlack() {
setDes(" ShortBlack ");
setPrice(40.0F);
}
}
public class Decorator extends Drink {
private Drink obj;
// 组合
public Decorator(Drink obj) {
this.obj = obj;
}
@Override
public float cost() {
// getPrice 拿到自己的价格
return super.getPrice() + obj.cost();
}
@Override
public String getDes() {
// 被装饰者描述信息
return super.des + " " + super.getPrice() + " && " + obj.getDes();
}
}
//具体的 Decorator 这里就是调味品
public class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
setDes(" 巧克力 ");
setPrice(3.0F);
}
}
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
setDes(" 牛奶 ");
setPrice(13.0F);
}
}
public class Soy extends Decorator {
public Soy(Drink obj) {
super(obj);
setDes(" 豆浆 ");
setPrice(2.0F);
}
}
测试
public class Client {
public static void main(String[] args) {
// 装饰者模式下订单:2份巧克力+1份牛奶的LongBlack
// 1.点一份 Long Black
Drink order = new LongBlack();
System.out.println("费用:" + order.cost());
System.out.println("描述:" + order.des);
// 2,加一份牛奶
order = new Milk(order);
System.out.println("加入一份牛奶 费用:" + order.cost());
System.out.println("加入一份牛奶 描述:" + order.getDes());
// 3,再加一份巧克力
order = new Chocolate(order);
System.out.println("加入一份巧克力 费用:" + order.cost());
System.out.println("加入一份巧克力 描述:" + order.getDes());
// 4,再加一份巧克力
order = new Chocolate(order);
System.out.println("加入一份巧克力 费用:" + order.cost());
System.out.println("加入一份巧克力 描述:" + order.getDes());
}
}
打印结果
费用:60.0
描述: 美式咖啡
加入一份牛奶 费用:73.0
加入一份牛奶 描述: 牛奶 13.0 && 美式咖啡
加入一份巧克力 费用:76.0
加入一份巧克力 描述: 巧克力 3.0 && 牛奶 13.0 && 美式咖啡
加入一份巧克力 费用:79.0
加入一份巧克力 描述: 巧克力 3.0 && 巧克力 3.0 && 牛奶 13.0 && 美式咖啡
装饰者模式再JDK源码的分析
Java的IO结构 FilterInputStream就是一个装饰者
说明
- InputStream 是抽象类, 类似我们前面讲的 Drink
- FileInputStream 是 InputStream 子类,类似我们前面的 DeCaf, LongBlack
- FilterInputStream 是 InputStream 子类:类似我们前面 的 Decorator 修饰者
- DataInputStream 是 FilterInputStream 子类,具体的修饰者,类似前面的 Milk, Soy 等
- FilterInputStream 类 有 protected volatile InputStream in; 即含被装饰者
- 分析得出在jdk 的io体系中,就是使用装饰者模式
public abstract class InputStream implements Closeable {}
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
)
public class DataInputStream extends FilterInputStream implements DataInput {
/**
* Creates a DataInputStream that uses the specified
* underlying InputStream.
*
* @param in the specified input stream
*/
public DataInputStream(InputStream in) {
super(in);
}
}