一、情景:
老王在卖的煎饼摊子开张了,主营产品有煎饼、鸡蛋、火腿。
问题:1、有顾客想买加了鸡蛋的煎饼、或者加了火腿、鸡蛋的煎饼,那么该如何改造呢?
二、情景后续
设计模式大佬、推荐他用装饰者模式,进行包装、包装出带有鸡蛋的煎饼
三、装饰者模式(Decorator)
- 定义:动态的将责任附加到对象上若老扩展功能,装饰者提供老比继承更有弹性的替代方案
- 重要组件
- Component 被包装的原始组件
- Decorator 实现与原始组件相同的接口,并且组合了一个原始组件的引用
四、代码演示
4.1类图
4.2 煎饼、鸡蛋、火腿公共接口(Component)
/**
* @author liuzihao
* @create 2020-10-07-11:45
* 煎饼摊子基本接口
*/
public interface JbComponent {
/**
* 描述
* @return
*/
public String desc();
/**
* 价格
* @return
*/
public BigDecimal price();
}
4.3 各自的实现(ConcreteComponent)
/**
* @author liuzihao
* @create 2020-10-07-11:48
* 鸡蛋
*/
public class JbComponenteEgg implements JbComponent {
@Override
public String desc() {
return "鸡蛋";
}
@Override
public BigDecimal price() {
return new BigDecimal("1");
}
}
/**
* @author liuzihao
* @create 2020-10-07-11:47
*/
public class JbComponentPancakes implements JbComponent{
@Override
public String desc() {
return "煎饼";
}
@Override
public BigDecimal price() {
return new BigDecimal(2);
}
}
/**
* @author liuzihao
* @create 2020-10-07-11:48
*/
public class JbComponenthHotDog implements JbComponent {
@Override
public String desc() {
return "火腿";
}
@Override
public BigDecimal price() {
return new BigDecimal(1);
}
}
4.4 装饰者——带有鸡蛋煎饼(ConcreteDecoratoerA)
/**
* @author liuzihao
* @create 2020-10-07-11:51
*/
public class DecoratorPancakesWithEgg implements JbComponent {
private JbComponent jbComponent;
public DecoratorPancakesWithEgg(JbComponent jbComponent) {
this.jbComponent = jbComponent;
}
@Override
public String desc() {
return jbComponent.desc() + "\t" + "加鸡蛋";
}
@Override
public BigDecimal price() {
return jbComponent.price().add(BigDecimal.ONE);
}
}
4.5 装饰者——带有鸡蛋、火腿的煎饼(ConcreteDecoratoerB)
/**
* @author liuzihao
* @create 2020-10-07-11:54
*/
public class DecoratorPancakesWithHotDog implements JbComponent{
// 传入已经加了鸡蛋的煎饼
private JbComponent jbComponent;
public DecoratorPancakesWithHotDog(JbComponent jbComponent) {
this.jbComponent = jbComponent;
}
@Override
public String desc() {
return jbComponent.desc() +"\t" + "加热狗";
}
@Override
public BigDecimal price() {
return jbComponent.price().add(BigDecimal.ONE);
}
}
4.6 代码测试
public class DemoMain {
public static void main(String[] args) {
JbComponent jbComponent1 = new JbComponenthHotDog();
System.out.println("卖" + jbComponent1.desc() + "\t 价格" +jbComponent1.price());
JbComponent jbComponent2 = new JbComponenteEgg();
System.out.println("卖" + jbComponent2.desc() + "\t 价格" +jbComponent2.price());
JbComponent jbComponent3 = new JbComponentPancakes();
System.out.println("卖" + jbComponent3.desc() + "\t 价格" +jbComponent3.price());
System.out.println("==开始卖包装产品==");
JbComponent jbComponent4 = new DecoratorPancakesWithEgg(jbComponent3);
System.out.println("卖" + jbComponent4.desc() + "\t 价格" +jbComponent4.price());
JbComponent jbComponent5 = new DecoratorPancakesWithEgg(jbComponent4);
System.out.println("卖" + jbComponent5.desc() + "\t 价格" +jbComponent5.price());
}
}
五、小结
5.1改造之后的煎饼摊子
5.2总结
- 装饰者模式同继承一样,可以扩展行为,这符合开闭原则,但是有一个不好的地方就是这样会到账设计中出现很多小对象,程序的复杂性会增加。
- 装饰者可以不断的叠加,例如上述案例中,可以用完包装完鸡蛋后,继续包装鸡蛋、不断重复包装行为。