当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 图解Java设计模式之装饰者模式

图解Java设计模式之装饰者模式

2020年03月23日  | 移动技术网IT编程  | 我要评论

星巴克咖啡订单项目(咖啡馆)

1)咖啡种类/单品咖啡 :espresso(意大利浓咖啡)、shortblack、longblack(美式咖啡)、decaf(无因咖啡)
2)调料 :milk、soy(豆浆)、chocolate
3)要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
4)使用oo的来计算不同种类咖啡的费用 :客户可以点单品咖啡,也可以单品咖啡 + 调料组合。

方案 1 - 解决星巴克咖啡订单项目

在这里插入图片描述

方案1 - 解决星巴克咖啡订单问题分析

1)drink是一个抽象类,表示饮料
2)des就是对咖啡的描述,比如咖啡的名字
3)cost()方法就是计算费用,drink类中做成一个抽象方法
4)decaf就是单品咖啡,继承drink,并实现cost
5)espress&&milk就是单品咖啡 + 调料,这个组合很多
6)问题 :这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸。

方案 2 - 解决星巴克咖啡订单(好点)

1)前面分析到方案1因为咖啡单品 + 调料组合会造成类的倍增,因此可以做改进,将调料内置到drink类,这样就不会造成类数量过多。从而提高项目的维护性。
2)说明 :milk,soy,chocolate可以设计为boolean,表示是否要添加相应的调料。
在这里插入图片描述

方案2 - 解决星巴克咖啡订单问题分析

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方法进行一个费用的叠加计算,递归的计算价格

装饰者模式下的订单 :2份巧克力 + 一份牛奶的longblack

在这里插入图片描述
说明 :
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);
	}
	
}

装饰者模式在jdk应用的源码分析

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体系中,就是使用的装饰者模式
在这里插入图片描述
在这里插入图片描述

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网