图解Java设计模式之装饰者模式
图解java设计模式之装饰者模式
1)咖啡种类/单品咖啡 :espresso(意大利浓咖啡)、shortblack、longblack(美式咖啡)、decaf(无因咖啡)
2)调料 :milk、soy(豆浆)、chocolate
3)要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
4)使用oo的来计算不同种类咖啡的费用 :客户可以点单品咖啡,也可以单品咖啡 + 调料组合。
1)drink是一个抽象类,表示饮料
2)des就是对咖啡的描述,比如咖啡的名字
3)cost()方法就是计算费用,drink类中做成一个抽象方法
4)decaf就是单品咖啡,继承drink,并实现cost
5)espress&&milk就是单品咖啡 + 调料,这个组合很多
6)问题 :这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸。
1)前面分析到方案1因为咖啡单品 + 调料组合会造成类的倍增,因此可以做改进,将调料内置到drink类,这样就不会造成类数量过多。从而提高项目的维护性。
2)说明 :milk,soy,chocolate可以设计为boolean,表示是否要添加相应的调料。
1)方案2可以控制类的数量,不至于造成很多的类
2)在增加或者删除调料种类时,代码的维护量很大
3)考虑到用户可以添加多份调料时,可以将hasmilk返回一个对于int
4)考虑使用装饰者模式
1)装饰者模式 :动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现类开闭原则(ocp)。
1)装饰者模式就像打包一个快递
主体 :比如 :陶瓷、衣服(component)//被装饰者
包装 :比如 :报纸填充、塑料泡沫、纸板、木板(decorator装饰者)
2)component主体 :比如类似前面的drink
3)concretecomponent和decorator
concretecomponent :具体的主体,
比如前面的各个单品咖啡
4)decorator :装饰者,比如各调料。
如图的component和concretecomponent之间,如果concretecomponent类很多,还可以设计一个缓存层,将共有的部分提取出来,抽象成一个类。
说明 :
1)drink类就是前面说的抽象类,component
2)shortblack就单品咖啡
3)decorator是一个装饰类,含有一个被装饰的对象(drink drink)
4)decorator的cost方法进行一个费用的叠加计算,递归的计算价格
说明 :
1)milk包含类longblack
2)一份chocolate包含了(milk + longblack)
3)一份chocolate包含了(chocolate + milk + longblack)
4)这样不管是什么形式的单品咖啡 + 调料组合,通过递归方式可以方便的组合和维护。
package com.example.demo.decorator; public abstract class drink { /** * 描述 */ public string des; private float price = 0.0f; /** * 计算费用的抽象方法 * 子类去实现 * @return */ public abstract float cost(); public string getdes() { return des; } public void setdes(string des) { this.des = des; } public float getprice() { return price; } public void setprice(float price) { this.price = price; } } package com.example.demo.decorator; public class decorator extends drink{ private drink obj; /** * 组合的方式 * @param objdrink */ public decorator(drink objdrink) { this.obj = objdrink; } @override public float cost() { // todo auto-generated method stub // getprice 自己价格 return super.getprice() + obj.cost(); } @override public string getdes() { // todo auto-generated method stub // obj.getdes() 输出被装饰者的信息 return des + " " + getprice() + " && " + obj.getdes(); } } package com.example.demo.decorator; /** * 具体的decotator,这里就是调味品 * @author zhaozhaohai * */ public class chocolate extends decorator{ public chocolate(drink obj) { super(obj); setdes(" 巧克力 "); // 调位品的价格 setprice(3.0f); } } package com.example.demo.decorator; public class coffee extends drink{ @override public float cost() { // todo auto-generated method stub return super.getprice(); } } package com.example.demo.decorator; public class decof extends coffee{ public decof() { setdes(" 无因咖啡 "); setprice(9.6f); } } package com.example.demo.decorator; public class coffeebar { public static void main(string[] args) { // 装饰者模式下的订单 :2份巧克力 + 一份牛奶的longblack // 1. 点一份 longblack drink orderdrink = new longblack(); system.out.println("费用 1 = " + orderdrink.cost()); system.out.println("描述 = " + orderdrink.getdes()); // 2. orderdrink 加一份牛奶 orderdrink = new milk(orderdrink); system.out.println("order 加一份牛奶 费用 = " + orderdrink.cost()); system.out.println("order 加一份牛奶 描述 = " + orderdrink.getdes()); // 3. orderdrink 加一份巧克力 orderdrink = new chocolate(orderdrink); system.out.println("order 加一份牛奶 加一份巧克力 费用 = " + orderdrink.cost()); system.out.println("order 加一份牛奶 加一份巧克力 描述 = " + orderdrink.getdes()); // 4. orderdrink 第二份巧克力 orderdrink = new chocolate(orderdrink); system.out.println("order 加一份牛奶 加2份巧克力 费用 = " + orderdrink.cost()); system.out.println("order 加一份牛奶 加2份巧克力 描述 = " + orderdrink.getdes()); system.out.println("========================="); drink drink2 = new decof(); system.out.println("drink2 无因咖啡 费用 = " + drink2.cost()); system.out.println("drink2 无因咖啡 描述 = " + drink2.getdes()); drink2 = new milk(drink2); system.out.println("order2 无因咖啡 加入一份牛奶 费用 = " + drink2.cost()); system.out.println("order2 无因咖啡 加入一份牛奶 描述 = " + drink2.getdes()); } } package com.example.demo.decorator; public class espresso extends coffee{ public espresso() { setdes(" 意大利咖啡 "); setprice(6.6f); } } package com.example.demo.decorator; public class longblack extends coffee{ public longblack() { setdes(" longblack "); setprice(5.0f); } } package com.example.demo.decorator; public class milk extends decorator{ public milk(drink obj) { super(obj); setdes(" 牛奶 "); setprice(2.0f); } } package com.example.demo.decorator; public class shortblack extends coffee{ public shortblack() { setdes(" shortblack "); setprice(8.0f); } } package com.example.demo.decorator; public class soy extends decorator{ public soy(drink obj) { super(obj); setdes(" 豆浆 "); setprice(1.5f); } }
java的io结构,filterinputstream就是一个装饰者
说明 :
(1)inputstream是抽象类,类似前面的drink
(2)fileinputstream是inputstream子类,类似前面decaf,longblack
(3)filterinputstream是inputstream子类 :类似前面的decorator装饰者
(4)datainputstream是filterinputstream 子类,具体的装饰者,类似前面的milk,soy等
(5)filterinputstream类有protected volatile inputstream in;即含被装饰者
jdk的io体系中,就是使用的装饰者模式