早晨有时候会去附近煎饼店买煎饼,煎饼店有卖咸味煎饼、甜味煎饼、无味煎饼。在煎饼制作的过程中,煎饼阿姨会问,"需要添加点什么吗"之类的话,我若选择咸味味煎饼加鸡蛋加火腿的时候,我需要付给阿姨的钱金额=咸味烧饼的钱+鸡蛋的钱+火腿的钱。现有需求:为煎饼店开发一套点餐系统,自动为顾客所点的不同口味且添加了不同添加辅料(鸡蛋、火腿、大葱、熏肉、生菜等)的煎饼算出最终售价。当我们看到如下图所示的那么些类,肯定会很烦恼。

这还仅仅只考虑三种辅料(鸡蛋,火腿,熏肉),当需要考虑大葱,生菜等,类一下子增多了很多很多。很明显,我们不可以采用此种方法。
当我们编写虚类Pancake,代码:
package com.raze.progress;
/**
* @author DJM
* @version 1.0
*/
public abstract class Pancake {
private String description;
private Boolean egg;
private Boolean ham;
private Boolean pork;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getEgg() {
return egg;
}
public void setEgg(Boolean egg) {
this.egg = egg;
}
public Boolean getHam() {
return ham;
}
public void setHam(Boolean ham) {
this.ham = ham;
}
public Boolean getPork() {
return pork;
}
public void setPork(Boolean pork) {
this.pork = pork;
}
public abstract float cost();
}
这样的弊端也很明显,首先根据开闭原则(Open close principle)的要求,对扩展开放,对修改关闭。这样就已不适用,因为当煎饼店添加了新的辅料,我们不得不修改类Pancake类。另外,当客户点了两个及以上的鸡蛋的时候,这种方法彻底瘫痪了。所以这种方法,也需要舍弃。
我编写了一个虚类Pancake,代码如下:
package com.raze.decorator.component;
/**
* @author DJM
* @version 1.0
*/
public abstract class Pancake {
private String description;
private Float price;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public abstract float cost();
}
并编写三个继承了虚类Pancake的子类,具体代码如下:
package com.raze.decorator.component.concrete;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.raze.decorator.component.Pancake;
/**
* 无添加煎饼
* @author DJM
* @version 1.0
*/
public class FanclPancake extends Pancake {
private static final Logger logger = LoggerFactory.getLogger(FanclPancake.class);
public FanclPancake(){
setDescription("FanclPancake");
setPrice(3.0f);
}
@Override
public float cost() {
logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
return getPrice();
}
}
package com.raze.decorator.component.concrete;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.raze.decorator.component.Pancake;
/**
* 咸煎饼
* @author DJM
* @version 1.0
*/
public class SalinePackage extends Pancake {
private static final Logger logger = LoggerFactory.getLogger(SalinePackage.class);
public SalinePackage() {
setDescription("SalinePackage");
setPrice(4.0f);
}
@Override
public float cost() {
logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
return getPrice();
}
}
package com.raze.decorator.component.concrete;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.raze.decorator.component.Pancake;
/**
* 甜煎饼
* @author DJM
* @version 1.0
*/
public class SugarPancake extends Pancake {
private static final Logger logger = LoggerFactory.getLogger(SugarPancake.class);
public SugarPancake(){
setDescription("SugarPancake");
setPrice(3.5f);
}
@Override
public float cost() {
logger.info("The pancake of {} costs {} yuan.", getDescription(), getPrice());
return getPrice();
}
}
定义一个装饰类Decorator,代码:
package com.raze.decorator.decorator;
import com.raze.decorator.component.Pancake;
/**
* 装饰者
* @author DJM
* @version 1.0
*/
public abstract class Decorator extends Pancake {
private Pancake pancake;
public Pancake getPancake() {
return pancake;
}
public void setPancake(Pancake pancake) {
this.pancake = pancake;
}
}
并为辅料定义类,所有的类如下图:

选出一个类Vegetable的代码进行展示:
package com.raze.decorator.decorator.concrete;
import com.raze.decorator.component.Pancake;
import com.raze.decorator.decorator.Decorator;
/**
* 生菜
* @author DJM
* @version 1.0
*/
public class Vegetable extends Decorator {
public Vegetable(Pancake pancake) {
setPancake(pancake);
}
@Override
public float cost() {
return super.getPancake().cost()+1.0f;
}
}
现在进行测试,具体代码如下:
package com.raze.decorator;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.raze.decorator.component.Pancake;
import com.raze.decorator.component.concrete.FanclPancake;
import com.raze.decorator.decorator.Decorator;
import com.raze.decorator.decorator.concrete.Egg;
import com.raze.decorator.decorator.concrete.Ham;
import com.raze.decorator.decorator.concrete.Pork;
import com.raze.decorator.decorator.concrete.Vegetable;
public class MyDecoratorTest {
private static final Logger logger = LoggerFactory.getLogger(MyDecoratorTest.class);
@Test
public void decorator(){
Pancake pancake = new FanclPancake();
float myCost = pancake.cost();
logger.info("The pancake costs {} yuan.", myCost);
Decorator decorator = new Vegetable(pancake);
myCost = decorator.cost();
logger.info("The pancake costs {} yuan.", myCost);
decorator = new Egg(pancake);
myCost = decorator.cost();
logger.info("The pancake costs {} yuan.", myCost);
decorator = new Ham(decorator);
myCost = decorator.cost();
logger.info("The pancake costs {} yuan.", myCost);
decorator = new Pork(decorator);
myCost = decorator.cost();
logger.info("The pancake costs {} yuan.", myCost);
decorator = new Pork(decorator);
myCost = decorator.cost();
logger.info("The pancake costs {} yuan.", myCost);
}
}
控制台打印的结果为:

认真思考下图,可装饰者设计模式的思路得到新的梳理:

原文:http://my.oschina.net/dengjianming/blog/509306