欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-09-04 21:41:49
图解Java设计模式之装饰者模式 星巴克咖啡订单项目(咖啡馆) 方案 1 - 解决星巴克咖啡订单项目 方案1 - 解决星巴克咖啡订单问题分析 方案 2 - 解决星巴克咖啡订单(好点) 方案2 - 解决星巴克咖啡订单问题分析 装饰者模式定义 装饰者模式原理 装饰者模式解决星巴克咖啡订单 装饰者模式下的 ......

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

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

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

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

方案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,表示是否要添加相应的调料。
图解Java设计模式之装饰者模式

方案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类很多,还可以设计一个缓存层,将共有的部分提取出来,抽象成一个类。
图解Java设计模式之装饰者模式

装饰者模式解决星巴克咖啡订单

图解Java设计模式之装饰者模式
说明 :
1)drink类就是前面说的抽象类,component
2)shortblack就单品咖啡
3)decorator是一个装饰类,含有一个被装饰的对象(drink drink)
4)decorator的cost方法进行一个费用的叠加计算,递归的计算价格

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

图解Java设计模式之装饰者模式
说明 :
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就是一个装饰者
图解Java设计模式之装饰者模式
说明 :
(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体系中,就是使用的装饰者模式
图解Java设计模式之装饰者模式
图解Java设计模式之装饰者模式