第5篇 装饰者模式

来源:互联网 发布:大宝防晒霜如何 知乎 编辑:程序博客网 时间:2024/05/01 22:01

1.什么是装饰者模式--从安徽牛肉板面说起

吃过安徽牛肉板面的人可能会对安徽牛肉板面的味道赞不绝口.是的,本人最喜欢宽面条的安徽牛肉板面,最好再加一个卤蛋,味道想必是很好的.安徽牛肉板面的面条有宽面条,窄面条和细面条(龙须面)三种.然后配料呢也是有很多种的,比如你可以选择加卤蛋、香肠、豆皮、辣椒等.那么问题来了.如果让我们来设计这些面条的类以保证用户要了那种面条以后可以快速得出价格.哦,忘了说了下面使他们的价目表:

牛肉板面的女老板说他们绝对童叟无欺,价格公正.....

那么,我们的类应该如何设计呢??你可以这样:

有一个面条类,

下边有宽面条,窄面条,细面条继承他.

然后呢这三个下边再有加香肠的宽面条,加卤蛋的宽面条,加豆皮的宽面条...

   加香肠的窄面条,加卤蛋的窄面条,加豆皮的窄面条...

     ....

这样看来的话,也是可以的.但是如果有个顾客的要求是加两个卤蛋,加一个卤蛋一个香肠呢??如此这般的话我们还要定义加两个卤蛋的宽面条...这个时候我们的装饰者模式就出场啦!

先看一下装饰者模式的定义,随后呢,我们就用它来解决安徽牛肉板面老板的噩梦:

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

简单的说呢,我们使用一个对象来"装饰"另外一个对象,使之具有更强的灵活性.就好像说:有个顾客到了店里,要了一碗加香肠的宽的牛肉板面,我们会用香肠来装饰我们的宽面条以得到加香肠的宽的牛肉板面.如果他在想加一个卤蛋.我们就用卤蛋来装饰此时他的牛肉板面,就会得到加一个香肠一个卤蛋的牛肉板面:

       

2.如何定义装饰者模式呢?

装饰者模式需要有一个具体的组件,用以装饰的接口,装饰的对象(实现装饰的接口),装饰的接口和具体的组件需要有共同的父类(为什么这个稍后在议)抽象的组件.用我们的装饰的对象来装饰我们具体的组件.下面使他们的类图:


下面我们就用代码以我们的牛肉板面为例子创建我们的类来试试看.

Noddle.javapackage com.john;public abstract class Noddle {String name = "noddle";public String whichKind(){return name;}public abstract double cost();}

BroadNoddle.javapackage com.john;public class BroadNoddle extends Noddle {public BroadNoddle(){super.name = "宽面条";}public double cost() {return 8.0;}}

PettyNoddle.javapackage com.john;public class PettyNoddle extends Noddle {public PettyNoddle(){name = "窄面条";}public double cost() {return 7.0;}}

ThinNoddle.javapackage com.john;public class ThinNoddle extends Noddle {public ThinNoddle(){name = "细面条";}public double cost() {return 9.0;}}
Condiment.javapackage com.john;public abstract class Condiment extends Noddle {public abstract String whichKind();}


Egg.javapackage com.john;public class Egg extends Condiment {Noddle noddle;//要装饰的类public Egg(Noddle noddle){this.noddle = noddle;}public String whichKind() {return (this.noddle.whichKind()+"加一个蛋");}public double cost(){return noddle.cost()+2.0;}}


Sausage.javapackage com.john;public class Sausage extends Condiment {Noddle noddle;//要装饰的类public Sausage(Noddle noddle){this.noddle = noddle;}public String whichKind() {return (this.noddle.whichKind()+"加一根香肠");}public double cost(){return noddle.cost()+1.5;}}

最后是我们的测试类:

Driver.javapackage com.john;public class Driver {public static void main(String[] args) {//System.out.println("来一碗宽面条,加一根肠,一个卤蛋");Noddle n = new BroadNoddle();System.out.println(n.whichKind()+"  "+n.cost());Noddle noddle = new BroadNoddle();noddle = new Sausage(noddle);noddle = new Egg(noddle);System.out.println(noddle.whichKind());System.out.println("价格:"+noddle.cost());}}


测试结果: 

                                                       
 



看看,是不是能够正常的计算出每一种面的价格了呢??

3.总结

相比于继承来说,我们的装饰者模式更加灵活了.可以在程序运行的时候来自定义我们的类!!

0 0