Java设计模式——装饰者模式 概述 版权说明 使用环境 定义 功能优点 思路分析 类图展示 代码展示 运行图例 源码下载

本章可以称为“给爱用继承的人一个全新的设计眼界”。我们即将再度探讨典型滥用问题。你将在本章学到如何使用对象组合的方式,做到在运行时装饰类。为什么呢?一旦你熟悉了装饰者的技巧,你将能够在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。

                                                                           ——《Head First 设计模式》


版权说明

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
本文作者:Q-WHai
发表日期: 2015年5月25日
本文链接:http://blog.csdn.net/lemon_tree12138/article/details/45870027
来源:CSDN
更多内容:分类 >> 设计模式


使用环境

当我们有多种类型的事物,且每一种事物下面又有很多小的、细的分类。这些分类之间可以随意组合时(例如一种饮料有一个主原料和一些配料、一道菜会有一个主原料加上一些配料或是去装饰一个房间等等),我们就可以想一下是不是可以用装饰模式来实现。下面就《Head First 设计模式》中的例子星巴兹的咖啡说简单说明一下。


定义

装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。


功能优点

利用组合维护代码,通过动态地组合对象,可以写新的代码添加新功能,而无须修改现有代码。

 

思路分析

  在星巴兹的咖啡店里,有多种咖啡,和多种调料。如果我们选择一种咖啡另外配上一种或是几种配料(主要主是一个被装饰者和多个装饰者)。那么我们如何对这些咖啡和配料进行收费呢(这里采用收费是一个好的举例,当然也可以是其他的一些相同的事件)?如果你说我们对每一种可选搭配可以封装,天呐,那该会有多少个类啊。还有一点就是,如果咖啡店里如果有一种咖啡或是配料价格有变动,或是需要新添加一种咖啡或是配料,又该怎么办呢?

  其实本文的模式就有一种很好的解决办法:我们不再使用继承,因为继承可能会导致类爆炸的。我们试想一下,能不能把咖啡店中的的所有原料(包括主原料和所有配料)都看成是一种东西(原料)。这样我们就可以在相互组合的过程中动态实现某些功能。可能你会问为什么要把其看成是一种东西,这样做的目的是为了在所有原料中实现同一功能,且无关代码中的组合顺序。

 

类图展示

这里为了方便起见,只绘制出了一部分内容,略去了一些重复或无关痛痒的部分。

Java设计模式——装饰者模式
概述
版权说明
使用环境
定义
功能优点
思路分析
类图展示
代码展示
运行图例
源码下载

当然,你也可以把上面咖啡那4个类再封一层。这里我就书中的内容做了一个原样输出。

从类图中可以看到 Milk 类持有了一个 Beverage 的引用。而对于 Beverage 而言是一个抽象类,正常的咖啡类都要继承自这个类。也就是说装饰者类 Milk 持有了全部的咖啡类,通过这样一层的聚合,这里的 Milk 类就可以对原先的 DarkRoast 类进行包装装饰。


代码展示

Beverage.java

public abstract class Beverage {

	public String mDescription = "UnKnown Beverage";
	private int size = 0;
	
	public String getDescription() {
		return mDescription;
	}
	
	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

	public abstract double cost();
}
CondimentDecorator.java

public abstract class CondimentDecorator extends Beverage {

	@Override
	public double cost() {
		return 0;
	}

	public abstract String getDescription();
}
DarkRoast.java

public class DarkRoast extends Beverage {

	private double mCost = 0.99;
	
	public DarkRoast() {
		mDescription = "Dark Roast Coffee";
	}

	@Override
	public double cost() {
		return mCost;
	}

}
Milk.java

public class Milk extends CondimentDecorator {

	private Beverage mBeverage = null;
	private double mCost = 0.10;
	
	public Milk(Beverage beverage) {
		mBeverage = beverage;
	}

	@Override
	public String getDescription() {
		return mBeverage.getDescription() + ", Milk";
	}
	
	public double cost() {
		return mCost + mBeverage.cost();
	}

}
StarbuzzCoffee.java

public class StarbuzzCoffee {

	public static void main(String[] args) {
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription() + " $" + beverage.cost());
		
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
		
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage3);
		beverage3 = new Mocha(beverage3);
		beverage3 = new Whip(beverage3);
		System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
	}
}

行图例

Java设计模式——装饰者模式
概述
版权说明
使用环境
定义
功能优点
思路分析
类图展示
代码展示
运行图例
源码下载

源码下载

https://github.com/William-Hai/DesignPatternCollections