在本章你将学到如何使用对象组合方式,做到在运行时装饰类。
今天我们项目例子是一家咖啡店,让我们先来看看这个项目的类图吧。
购买咖啡时,也可以加入各种调料,服务员会根据加入的调料收取不同的费用,所以订单系统必须考虑到这些调料部分。
让我们来看一下下面这种设计结构。
是不是看了上面这个结构,虽然不知道怎么样,但是总感觉有什么问题对吧,让我们来看看上面这个结构存在什么问题吧。
1:调料价钱的改变会使我们更改现有代码。
2:一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法。
3:以后可能会开发出新饮料,某些调料可能并不合适,但是在这个设计方式中,子类仍将继承那些不合适的方法。
我们就先列举一些问题,当然还有其他问题小伙伴们可以自己去挖掘哦。
到了这里,我们就要提出一个非常重要的设计原则了:
类应该对扩展开放,对修改关闭。
接下来让我们看下装饰者模式是怎么样的吧:
是不是一下子就明白怎么回事了,我们来介绍一下装饰者模式的一些概念吧:
1:装饰者和被装饰对象有相同的超类型。
2:你可以用一个或多个装饰者包装一个对象。
3:既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象的场合,可以用装饰过的对象代替它。
4:装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
5:对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来修饰对象。
装饰者模式定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
装饰者模式类图:
利用装饰者模式后项目的类图:
接下来我们就要开始实现我们的具体代码了。
Beverage类:
public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost();}CondimentDecorator类:public abstract class CondimentDecorator extends Beverage{ public abstract String getDescription(); //所有的调料装饰者都必须重新实现getDescription方法}EsPResso类:public class Espresso extends Beverage{ public Espresso(){ description = "Espresso"; } public double cost(){ return 1.99; }}HouseBlend类:public class HouseBlend extends Beverage{ public HouseBlend(){ description = "House Blend Coffee"; } public double cost(){ return 0.89; }}这里我们就列举2种咖啡,其他的就不一一写出来了。接下来我们来写调料Mocha类:
public class Mocha extends CondimentDecorator{ Beverage beverage; //用一个实例变量来记录饮料,也就是被装饰者 public Mocha(Beverage beverage) { this.beverage = beverage; //让被装饰者被记录到实例变量中 } public String getDescription() { return beverage.getDescription() + ", Mocha"; } public double cost() { return 0.20+beverage.cost(); //返回计算后的价格 }}其他的调料也基本是这个结构。还记得上一章我们说过,java API里面有内置的观察者模式,其实装饰者模式也是一样的,java API也为我们提供了,那就是java I/O。
这里就不具体说明这个API的用法了,下面我们总结下这一章的内容:
1:继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。
2:在我们的设计中,应该允许行为可以扩展,而无须修改现有的代码。
3:组合和委托可用于在运行时动态地加上新的行为。
4:除了继承,装饰者模式也可以让我们扩展行为。
5:装饰者模式以为着一群装饰者类,这些类用来包装具体组件。
6:装饰者类反应出被装饰的组件类型。
7:装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
8:可以用无数个装饰者包装一个组件。
9:装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
10:装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。
新闻热点
疑难解答