三、装饰者模式

星巴克咖啡店问题

因为扩张速度太快,他们准备更新订单系统,以合乎他们的饮料供应要求。

他们原来的类设计是这样的。 。 。 。 。 。

Beverage   //(饮料)是一个抽象类,店内所提供的饮料都必须继承自此类

description   //这个变量,由子类设置,用来描述饮料,例如“超优深焙(Dark roast)咖啡豆”

getDescription()//返回description的内容

cost()        //抽象方法,返回饮料的价钱,每个子类必须实现

 

子类一                   子类二                   子类三                 子类四

HouseBlend         DarkRoast           Decaf                  Espresso

cost()                      cost()                    cost()                  cost()

 

购买咖啡时,也可以要求在其中加入各种调料,例如:蒸奶(Steamed Milk)、豆浆(soy)、摩卡(Mocha)或覆盖奶泡、星巴兹会根据所加入的调料收取不同的费用。所以订单系统必须考虑到这些调料部分。

 

这是他们的第一个尝试. .. . . . 


每个cost()方法将计算出咖啡加上订单上各种调料的价钱。很明显,如果牛奶的价格上扬,那么所有的用到牛奶的类都需要修改代码;

这样设计太复杂了,我们利用实例变量和继承,追踪这些调料来试试,先从Beverage基类下手,加上实例变量,代表是否加上调料(牛奶、豆浆、摩卡、奶泡. . . . . .)

 

Beverage

---------------------------

descrip

milk               //各种调料的新的布尔值

soy

mocha

whip

getDesc()

cost()    //不再是一个抽象方法,它计算要加入各种饮料的调料价钱,子类仍将覆盖cost,但是会调用超类的cost,计算出羁绊饮料加上调料的价钱。

 

hasMilk()//这些方法取得和设置调料的布尔值

setMilk()

hasSoy()

setSoy()

hasMocha()

setMocha()

hasWhip()

setWhip()

//其它有用的方法

-----------------------------------------------------

 

加入子类,每个类代表菜单上的一种饮料,每个cost()方法需要计算该饮料的价钱,然后通过调用超类的cost(),加入调料的价钱

子类一             子类二            子类三                 子类四

HouseBlend         DarkRoast           Decaf                 Espresso

cost()              cost()                cost()                 cost()

 

这种方法只需要五个类,

但是调料价钱的改变,调料类就要修改

一旦出现新的调料,我们需要加上新的方法,并改变超类中的Cost()方法

以后可能会开发出新饮料,对这些饮料而言,某些调料可能并不合适,但是在这个设计方式中,Tea子类仍将继承哪些不适合的方法,例如:haswhip,

万一顾客想要双倍摩卡,怎么办?

 

认识装饰者模式

我们了解到利用继承无法完全解决问题:类数量爆炸、设计死板,以及基类加入的新功能并不适用于所有的子类。

那我们要以饮料为主体,然后运行时以调料来装饰decorate饮料。

1、以DarkRoast对象开始,DarkRoast继承自Beverage,且有一个用来计算饮料价格的cost方法。

2、顾客想要摩卡(Mocha),所以建立一个Mocha对象,并用它将DarkRoast对象包起来

3、顾客也想要奶泡(whip),所以建立一个Whip装饰者,并用它将Mocha对象包起来。DarkRoast继承自Beverage,且有一个cost方法,用来计算饮料价钱。


4、现在,该为顾客算钱了。通过调用最外圈装饰者(Whip)的cost就可以办得到。Whip的cost会先委托它装饰的对象(Mocha)计算出价钱,然后再加上奶泡的价钱。

 

装饰者模式

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

 

 

装饰饮料框架


调料装饰者除了必须实现cost()之外,还必须实现getDescription()。

CondimentDecorator扩展自Beverage类,这样装饰者和被装饰者有共同的超类。

 

基类代码

先从Beverage类下手,这不需要改变星巴兹原始的设计。如下所示

public abstract class Beverage{

       Stringdescription = “Unknown beverage”;

       publicstring getDescription(){         //该方法已经实现,但是cost必须在子类中实现

              returndescription;

       }

       publicabstract double cost();

}

 

写调料代码

实现Condiment调料抽象类,也就是装饰者类:

public abstract class CondimentDecoratorextends beverage {

       publicabstract string getDescription();

}

 

 

写饮料代码

现在已经有了基类,开始实现一些饮料吧,先从浓缩咖啡(Espresso)开始。

public calss Espresso extends Beverage {

       publicEspresso() {

              description= “Espresso”;  //设置饮料的描述,description继承自Beverage

       }

       publicdouble cost() {

              return1.99;

       }

public calss HouseBlend extends Beverage {

       publicEs HouseBlend presso() {

              description= “House Blend Coffee”; 

       }

       publicdouble cost() {

              return0.89;    //另一种饮料

       }

 

 

写调料代码

现在我们来实现具体装饰者。先从摩卡下手:

 

public class Mocha extendsCondimentDecorator {

       Beveragebeverage;     //用一个实例变量记录饮料,也就是被装饰者。

       publicMocha(Beveragebeverage){

              this.beverage = beverage;

       }

       publicString getDescription(){

              returnbeverage.getDescription()+“,Mocha”;

       }

       publicdouble cost(){

              return0.20+ beverage.cost();//Mocha的价钱加上被装饰者的价钱

       }

}

 

供应咖啡

这是用来下订单的一些测试代码

public calss StarbuzzCoffee{

       publicstatic void main(String args[]) {

              Beveragebeverage = new Espresso();  //订一杯Espresso,不需要调料

              System.out.println(beverage.getDescrioption()+”$”+beverage.cost());

 

              Beveragebeverage2 = new DarkRoast();

              beverage2= new Mocha(beverage2);  //用Mocha装饰它

              beverage2= new Mocha(beverage2);  //用第二个Mocha装饰它

              beverage2= new Whip(beverage2);

              System.out.println(beverage2.getDescrioption()+”$”+beverage2.cost());

 

              Beveragebeverage3 = new houseBlend();

              beverage3= new Mocha(beverage3);  //用Mocha装饰它

              beverage3= new Mocha(beverage3);  //用第二个Mocha装饰它

              beverage3= new Whip(beverage3);

              System.out.println(beverage3.getDescrioption()+”$”+beverage3.cost());

 

 

实验结果:

% java StarbuzzCoffe

Espresso $1.99

Dark Roast Coffe、 Mocha、Mocha、Whip $1.49

House Blend Coffee、Soy、Mocha、Whip $1.34

%



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值