当前位置:网站首页>装饰模式--小美的生日蛋糕
装饰模式--小美的生日蛋糕
2022-06-11 10:54:00 【zhanyd】
生日蛋糕
过几天就是小美的生日了,小帅不敢怠慢,打算定一个奶油蛋糕,好好庆祝一下。
店里标准的奶油蛋糕上面就一层奶油,也没有其他的配料,看着不大气,万一小美不喜欢可就糟了。
小美喜欢吃水果,小帅就想在蛋糕上加点水果,就找老板商量:能不能多加几种水果,我可以另外加钱。
老板眉开眼笑:当然可以啊,我们这里有樱桃,草莓,火龙果你要加什么哦?
这是我们的价目表:
奶油蛋糕:200元
巧克力蛋糕:230元
樱桃:30元
草莓:15元
火龙果:10元
我们店有两种蛋糕,一种是奶油蛋糕,另一种是巧克力蛋糕,每种蛋糕都可以另外加水果哦。
正常套路
按照正常的套路,如果用代码实现买蛋糕的功能,我们一般会给每种蛋糕和水果组合设计一种类。
如果我们想要在奶油蛋糕上加樱桃就新建一个奶油蛋糕樱桃类(CreamCakeAndCherry);
如果奶油蛋糕上加草莓就新建一个奶油蛋糕草莓类(CreamCakeAndStrawberry);
如果巧克力蛋糕上加樱桃就新建一个巧克力蛋糕樱桃类(ChocolateCakeAndCherry)。
还有奶油蛋糕火龙果类,巧克力蛋糕草莓类,巧克力蛋糕火龙果类,如果蛋糕店又增加了一种千层蛋糕,还有千层蛋糕草莓类,千层蛋糕樱桃类。。。
如果再加几种水果。。。完蛋了,类已经爆炸了。。。

缺点
这么写有什么缺点呢?
1.最明显的是类太多了,看得眼花缭乱,增加了维护的成本。
2.一旦出现的新蛋糕或水果,又要增加一大堆类。
3.如果蛋糕和水果的价格改变了,要改很多很多类,严重违反了开闭原则:类应该对扩展开发,对修改封闭。
小帅作为一个有追求的程序员,当然不会满足这种做法,小帅想起了装饰模式,水果不是刚好装饰蛋糕的吗?正好符合装饰模式的应用场景,赶紧试一下吧。
装饰模式救场
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。
装饰模式的类图如下:
Component: 抽象构件
ConcreteComponent: 具体构件
Decorator: 抽象装饰类
ConcreteDecorator: 具体装饰类

这里要注意一下Decorator装饰类,它维持了一个指向component对象的指针,接口方法的实现,都是调用这个component对象的方法实现的,Decorator类本身只是调用了component对象已有的功能,这是装饰模式的精髓所在。
这么说有点不好理解,看一下下面的例子就能明白了。

蛋糕接口
public interface Cake {
public String getDescription();
public BigDecimal cost();
}
奶油蛋糕
public class CreamCake implements Cake{
public String getDescription() {
return "奶油蛋糕";
}
public BigDecimal cost() {
return BigDecimal.valueOf(200);
}
}
蛋糕装饰类
public class CakeDecorator implements Cake{
Cake cake;
public CakeDecorator(Cake cake) {
this.cake = cake;
}
public String getDescription() {
return cake.getDescription();
}
public BigDecimal cost() {
return cake.cost();
}
}
樱桃
public class Cherry extends CakeDecorator{
public Cherry(Cake cake) {
super(cake);
}
@Override
public String getDescription() {
return cake.getDescription() + ",添加樱桃";
}
@Override
public BigDecimal cost() {
return BigDecimal.valueOf(30).add(cake.cost());
}
}
草莓
public class Strawberry extends CakeDecorator{
public Strawberry(Cake cake) {
super(cake);
}
@Override
public String getDescription() {
return cake.getDescription() + ",添加草莓";
}
@Override
public BigDecimal cost() {
return BigDecimal.valueOf(15).add(cake.cost());
}
}
火龙果
public class DragonFruit extends CakeDecorator{
public DragonFruit(Cake cake) {
super(cake);
}
@Override
public String getDescription() {
return cake.getDescription() + ",添加火龙果";
}
@Override
public BigDecimal cost() {
return BigDecimal.valueOf(10).add(cake.cost());
}
}
测试类
public class Test {
public static void main(String[] args) {
// 标准奶油蛋糕
Cake cake = new CreamCake();
// 添加樱桃
cake = new Cherry(cake);
// 添加草莓
cake = new Strawberry(cake);
// 添加火龙果
cake = new DragonFruit(cake);
// 双份樱桃,土豪啊
cake = new Cherry(cake);
System.out.println(cake.getDescription());
System.out.println("合计:" + cake.cost());
}
}
测试结果
奶油蛋糕,添加樱桃,添加草莓,添加火龙果,添加樱桃
合计:285
调用过程如下:
装饰模式的调用链,看起来有点像递归调用,装饰类都是附加在其他类上的,但是最重要的还是调用链最底层的实现类。
总结
装饰模式的优点:
1.比继承更灵活,用继承实现的类似功能的话,会产生许多新类,就像上文提到的”类爆炸”。装饰模式可以提供了更加灵活的添加职责的方式,可以在运行时动态地新增和删除职责。
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
3.具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
装饰模式的缺点:
1.使用装饰模式进行系统设计时将产生很多小对象,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
2.这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
最后
小美吃着蛋糕,露出开心的笑容:好多樱桃哦,我好喜欢!
小帅:知道你喜欢吃水果,我特意让老板加了两份樱桃呢。
小美:程序员的心思果然细腻,哈哈。

边栏推荐
- SurroundDepth:自监督多摄像头环视深度估计
- MYSQL(九)
- Jerry's ble spp open pin_ Code function [chapter]
- Beginning an excellent emlog theme
- 2022北京国际营养健康产业博览会,第九届中国大健康产业展会
- Electron桌面端开发(开发一个闹钟【完结】)
- 杰理之获取 BLE 出现电压检测、ADC 检测不准【篇】
- SQL query statement optimization
- MySQL下载安装使用-完整详细步骤
- Why is Web3 a game changer for the "creator economy"
猜你喜欢

AI security and Privacy Forum issue 11 - stable learning: finding common ground between causal reasoning and machine learning

使用Yolov5训练好模型调用电脑自带摄像头时出现问题:TypeError: argument of type “int‘ is not iterable的解决方法

Shi Yigong: I was not interested in research until I graduated from my doctor's degree! I'm confused about the future, and I don't know what to do in the future

小 P 周刊 Vol.08

Using ribbon to realize client load balancing

Characteristics and classification of creation mode (single case, factory)

beginning一款非常优秀的emlog主题

Surrounddepth: self supervised multi camera look around depth estimation

Cloud development MBTI personality type test assistant wechat applet source code

Xiao P weekly Vol.08
随机推荐
Package component series - (I) - slots and dynamic components
IIHS tsp+ annual safety list released: 7 EVs were selected, and there are common problems in pedestrian AEB
使用国产MCU(国民技术 N32G031F8S7) 实现 PWM+DMA 控制 WS2812
封装组件系列-(一)-插槽及动态组件
C language course design
杰理之BLE SPP 开启 pin_code 功能【篇】
使用Labelimg制作VOC数据集或yolo数据集的入门方法
Leetcode (Sword finger offer) - 10- ii Frog jumping on steps
施一公:我直到博士毕业,对研究也没兴趣!对未来很迷茫,也不知道将来要干什么......
Interpretation of cube technology | past and present life of cube Rendering Design
SAP Spartacus Reference App Structure
MySQL download, installation and use - complete and detailed steps
Remote monitoring project offline log specification
杰理之获取 BLE 查看代码异常复位等异常情况原因【篇】
Writing the program into the microcontroller can control the forward and reverse rotation of the motor more conveniently and quickly
杰理之获取 BLE 出现电压检测、ADC 检测不准【篇】
Taking the cooperation between different banks as an example, the construction of small program ecology
正大期货主账户预4 周三信息汇总
恋爱时将房屋一半产权登记在女方名下,分手后想要回
Hardware Description Language HDL