1.什么是装饰者模式--从安徽牛肉板面说起
吃过安徽牛肉板面的人可能会对安徽牛肉板面的味道赞不绝口.是的,本人最喜欢宽面条的安徽牛肉板面,最 好再加一个卤蛋,味道想必是很好的.安徽牛肉板面的面条有宽面条,窄面条和细面条(龙须面)三种.然后配料呢也是有 很多种的,比如你可以选择加卤蛋、香肠、豆皮、辣椒等.那么问题来了.如果让我们来设计这些面条的类以保证用户 要了那种面条以后可以快速得出价格.哦,忘了说了下面使他们的价目表:
买牛肉板面的女老板说他们绝对童叟无欺,价格公正.....
那么,我们的类应该如何设计呢??你可以这样:
有一个面条类,
下边有宽面条,窄面条,细面条继承他.
然后呢这三个下边再有加香肠的宽面条,加卤蛋的宽面条,加豆皮的宽面条...
加香肠的窄面条,加卤蛋的窄面条,加豆皮的窄面条...
....
这样看来的话,也是可以的.但是如果有个顾客的要求是加两个卤蛋,加一个卤蛋一个香肠呢??如此这般的话我们还要定义加两个卤蛋的宽面条...这个时候我们的装饰者模式就出场啦!
先看一下装饰者模式的定义,随后呢,我们就用它来解决安徽牛肉板面老板的噩梦:
定义:动态地将责任附加到对象上,若要扩展对象,装饰者模式提供了比继承更有弹性的替代方案.
简单的说呢,我们使用一个对象来"装饰"另外一个对象,使之具有更强的灵活性.就好像说:有个顾客到了店里,要了一碗加香肠的宽的牛肉板面,我们会用香肠来装饰我们的宽面条以得到加香肠的宽的牛肉板面.如果他在想加一个卤蛋.我们就用卤蛋来装饰此时他的牛肉板面,就会得到加一个香肠一个卤蛋的牛肉板面:
2.如何定义装饰者模式呢?
装饰者模式需要有一个具体的组件,用以装饰的接口,装饰的对象(实现装饰的接口),装饰的接口和具体的组件需要有共同的父类(为什么这个稍后在议)抽象的组件.用我们的装饰的对象来装饰我们具体的组件.下面使他们的类图:
下面我们就用代码以我们的牛肉板面为例子创建我们的类来试试看.
Noddle.java
package com.john;
public abstract class Noddle {
String name = "noddle";
public String whichKind(){
return name;
}
public abstract double cost();
}
BroadNoddle.java
package com.john;
public class BroadNoddle extends Noddle {
public BroadNoddle(){
super.name = "宽面条";
}
public double cost() {
return 8.0;
}
}
PettyNoddle.java
package com.john;
public class PettyNoddle extends Noddle {
public PettyNoddle(){
name = "窄面条";
}
public double cost() {
return 7.0;
}
}
ThinNoddle.java
package com.john;
public class ThinNoddle extends Noddle {
public ThinNoddle(){
name = "细面条";
}
public double cost() {
return 9.0;
}
}
Condiment.java
package com.john;
public abstract class Condiment extends Noddle {
public abstract String whichKind();
}
Egg.java
package 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.java
package 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.java
package 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.总结
相比于继承来说,我们的装饰者模式更加灵活了.可以在程序运行的时候来自定义我们的类!!