早晨有时候会去附近煎饼店买煎饼,煎饼店有卖咸味煎饼、甜味煎饼、不加甜味也不加咸味的煎饼。在煎饼制作的过程中,煎饼阿姨会问,"需要添加点什么吗,有鸡蛋、火腿、熏肉......"之类的话。我若选择咸味味煎饼加鸡蛋加火腿的时候,我需要付给阿姨的钱金额=咸味烧饼的钱+鸡蛋的钱+火腿的钱。现有需求:为煎饼店开发一套订单系统,自动为顾客所点的不同口味且添加了不同添加辅料(鸡蛋、火腿、大葱、熏肉、生菜等)的煎饼算出最终售价。
当我们看到如下图所示的那么多的类,肯定会很觉得写那么多类的开发者很脑残。
这仅仅只考虑三种辅料(鸡蛋,火腿,熏肉),当需要考虑大葱,生菜等,类的数量迅速的增多了很多。很明显,这种方法是愚蠢的。
面对上面糟糕的方法,我们重新想出新的方法,来避免井喷式增长的类的问题。首先,编写虚类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和继承虚类Pancake的子类的中间层写了一个类ConcretePancake,具体代码如下:
package com.raze.decorator.component.concrete; import com.raze.decorator.component.Pancake; public class ConcretePancake extends Pancake{ @Override public float cost() { return getPrice(); } }
并编写三个继承了类ConcretePancake的子类,具体代码如下:
package com.raze.decorator.component.concrete; /** * 无添加煎饼 * @author DJM * @version 1.0 */ public class FanclPancake extends ConcretePancake { public FanclPancake(){ setDescription("FanclPancake"); setPrice(3.0f); } }
package com.raze.decorator.component.concrete; /** * 咸煎饼 * @author DJM * @version 1.0 */ public class SalinePackage extends ConcretePancake { public SalinePackage() { setDescription("SalinePackage"); setPrice(4.0f); } }
package com.raze.decorator.component.concrete; /** * 甜煎饼 * @author DJM * @version 1.0 */ public class SugarPancake extends ConcretePancake { public SugarPancake(){ setDescription("SugarPancake"); setPrice(3.5f); } }
定义一个装饰类Decorator,代码:
package com.raze.decorator.decorator; import com.raze.decorator.component.Pancake; /** * 装饰类 * @author DJM * @version 1.0 */ public class Decorator extends Pancake { private Pancake pancake; public Pancake getPancake() { return pancake; } public void setPancake(Pancake pancake) { this.pancake = pancake; } public Decorator(Pancake pancake){ this.pancake = pancake; } @Override public float cost() { return pancake.cost()+super.getPrice(); } @Override public String getDescription() { return pancake.getDescription().concat("-").concat(super.getDescription()); } }
并为辅料定义类,继承于类Decorator,所有的辅料类如下图:
选出一个类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) { super(pancake); setDescription("Vegetable"); setPrice(0.5f); } }
现在进行测试,具体代码如下:
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.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 MyPancakeTest { private static final Logger logger = LoggerFactory.getLogger(MyPancakeTest.class); @Test public void pancake(){ Pancake pancake = new FanclPancake(); float myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Vegetable(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Egg(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Ham(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Pork(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Pork(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); pancake = new Ham(pancake); myCost = pancake.cost(); logger.info("The pancake costs {} yuan.The description is {}.", myCost, pancake.getDescription()); } }
控制台打印的结果为:
根据类的关系,得到如下图: