设计模式(三)The_Decorator_Pattern(装饰者模式)
the Decorator Pattern
文章目录
概述
装饰者模式
实现的功能是在运行的时候使用object composition
对象组合,从而达能在不改变代码的情况下给对象以新的功能。
问题提出
如果你想要设计一个饮品的类,那么你可能设计如下:
- 一个抽象的Beverage
- description,是一个实例变量,可以使String字符串,每个继承的子类都有设置
- getDescription()
- cost(); 是一个抽象的方法,每个子类都需要自己定义他们的价格。
这样在每次新添加一个款饮品时,就可以直接继承并且重写cost();
这看起来很好,但是对于维护来说确实一个噩梦。
比如如果牛奶的价格上涨,那么所有关于牛奶做原材料的饮品都需要价格上调。
而且对于咖啡来说,可以添加不同的调味品,那么对于不同调味品的组合,就需要产生不同的子类,导致子类太多!
那么是否可以在超类/父类中实例化这些调味品,然后继承跟踪这些呢?
新:
Beverage:
- description
- milk boolean型
- soy
- mocha
- whip
- getDescription()
- cost() 现在cost方法不再是抽象的,这样能够计算通过调味品的状态来计算价格,子类也将会重写cost,但是他们会先调用super版本,来计算添加调配品后的基础价格。
- hasMilk();
- setMilk();
- hasSoy();
- 等等
原则:The Open-Closed Principle
Classes should be open for extension, but closed for modification;
类的设计应该对扩展开放,对修改关闭。
我们的目标是让类容易去在未修改代码的情况下去添加新的行为。一旦我们达成这样的设计,对于添加新的功能需求是平稳的并且可恢复的。
**注意:**小心选择需要扩展的代码区,到处使用Open-Closed Principle是没必要切浪费资源,增加代码复杂度,难于理解。
装饰模式
上边的解决方法仍然不是很好,可能产生类爆炸,不灵活的设计,或者在基类中添加一些不适用与所有子类的功能。
装饰者模式:对于咖啡的例子来说,我们在运行时动态添加调剂品,例如 :
- 创建一个DarkRoast子类
- 使用Mocha(摩卡)的类装饰一下
- 使用Whip(打泡)装饰
- 调用cost()函数,依靠代理(delegation)来添加调配品的价格
如何实现装饰
?delegation是如何产生的?
按照包装的思想考虑:
- 开始于DarkRoash 对象
- 消费者想要摩卡,我们构建一个Mocha的对象,并且包装DarkRoash对象。
- Whip同理
4.计算cost()时使用递归的思想。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LPQZHhOj-1576402836142)(_v_images/20191209112130384_10807.png =652x)]
实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ai43ULJI-1576402836144)(_v_images/20191209124139793_24032.png)]
有两个主要的基类,都是抽象类,分别是Beverage和CondimentDecorator, 其中CondimentDecorator又继承Beverage。
所有的饮品都继承Beverage, 所有的添加剂/调味品都继承CondimentDecorator.
在具体的CondimentDecorator的子类中,需要处理包装的功能。并且要保存Beverage变量。
//基类
public abstract class Beverage {
String description = “Unknown Beverage”;
public String getDescription() {
return description;
}
public abstract double cost();
}
//装饰器基类,继承Beverage
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
/*一些子类*/
//特浓
public class Espresso extends Beverage {
public Espresso() {
description = “Espresso”;
}
public double cost() {
return 1.99;
}
}
public class HouseBlend extends Beverage {
public HouseBlend() {
description = “House Blend Coffee”;
}
public double cost() {
return .89;
}
}
/*调味品*/
public class Mocha extends CondimentDecorator {
//包含实例变量,保存包装的对象
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + “, Mocha”;
}
public double cost() {
return .20 + beverage.cost();
}
}
/*使用*/
public class StarbuzzCoffee {
public static void main(String args[]) {
//特浓
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ “ $” + beverage.cost());
//DarkRoast
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ “ $” + beverage2.cost());
//HouseBlend();
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()
+ “ $” + beverage3.cost());
}
}
简单来说,就是把能够组合的分离出来,但是都有共同的基类。
上一篇: 游戏制作之路(6)创建角色行走的地面
下一篇: 获取组件与移动