今天就来写一下装饰者模式,该软考了,也该实习了,感觉心态静不下来,设计模式都是一些简单的小例子,但是看了这么久连简单的了解还没有完全搞定,深感惭愧,还是要安静下来,书中才有颜如玉~ ~ ~不扯了,下边进入正题
一、装饰者模式定义
在不修改原类的基础上,动态地扩展原来的对象的功能,装饰者提供了比继承更有弹性的替代方案:通过创建一个包装对象(装饰对象),来包裹真实的对象
二、装饰者模式特点
(1) 装饰者和被装饰者有相同的超类型
(2) 可以用一个或者多个装饰者包装一个对象
(3) 因为装饰者和被装饰者有相同超类型,则可以在任何需要原始对象(被包装的对象)的场合,用装饰过的对象代替它
(4) 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的(注意加粗部分)
(5) 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用某装饰者来装饰对象
三、装饰者模式的具体实现——设计咖啡店的订单管理系统
1、首先看下咖啡店原本的类设计:
Beverage类(抽象类):属性description由子类设置
每个子类实现cost抽象方法,返回各自价格
当然,在购买咖啡的时候,可以要求在其中加入各种调料:豆浆(Soy)、摩卡(Mocha)、奶泡(Whip)等等,咖啡店会根据加入调料收取不同的费用,所以订单系统需要考虑这些调料部分
解决方法(1):所以我们可以这样做,设计出这些类:
摩卡和奶泡深焙咖啡类、摩卡深焙咖啡类、豆浆浓缩咖啡类等等
可以看出来,我们根据调料和咖啡的种类要用排列组合计算到底需要多少类了。这简直就是”类爆炸“,制造了维护的噩梦
解决方法(2):重新设计Beverage(饮料)类如下
重新设计后的Beverage不再是一个抽象类而是一个具体类:
public class Beverage {
String description;
boolean milk;
boolean soy;
boolean mocha;
boolean whip;
double milkCost = 1.0;
double soyCost = 2.0;
double mochaCost = 3.0;
double whipCost = 4.0;
//获得描述
public String getDescription(){
return description;
}
//得到调料价格
public double cost(){
double condimentCost = 0.0;
if(isMilk()){
condimentCost += milkCost;
}
if(isMocha()){
condimentCost += mochaCost;
}
if(isSoy()){
condimentCost += soyCost;
}
if(isWhip()){
condimentCost += whipCost;
}
return condimentCost;
}
//省略milk、mocha、soy、whip的setter和getter方法
}
然后,实现DarkRoast(深焙咖啡类):
public class DarkRoast extends Beverage {
public DarkRoast(){
description = "我是深焙咖啡";
}
public double cost(){
return 1.99+super.cost();
}
}
然后我们写一个main函数:
public class Main {
public static void main(String[] args) {
//我想要一个加奶的深焙咖啡
T t = new T1();
t.setMilk(true);
System.out.println("加奶的深焙咖啡价格:"+t.cost());
}
}
打印出来结果:加奶的深焙咖啡价格:2.99 如此,我们就可以实现我们想要的了。但是,这里有一个很严重的问题:如果我们需要增加一个配料的话,我们就需要继续修改这个Beverage类了,这违反了”扩展开放,修改关闭的开—闭设计原则“。我们如何改良?
2、利用装饰者模式对系统进行重新构造
(1) 如果顾客想要摩卡和奶泡深焙咖啡,那么我们需要做的是
① 拿一个深焙咖啡对象
② 以摩卡对象装饰它
③ 以奶泡对象装饰它
④ 调用cost方法,并依赖委托将调料的价格加上去
步骤:
等到算钱的时候只需要调用最外层Whip的cost方法就可以办到
(2) 定义装饰者模式
3、使用装饰者模式实现咖啡店的订单系统:
Beverage.java
public abstract class Beverage {
protected String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
HouseBlend.java
//浓缩咖啡
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
public double cost() {
return .89;
}
}
DarkRoast.java
//深焙咖啡
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "DarkRoast";
}
public double cost() {
return .99;
}
}
Epresso.java
//浓缩咖啡
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
CondimentDecorator.java
//配料类的超类
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
Mocha.java
//摩卡(配料)
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();
}
}
Soy.java
//豆浆(配料)
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return .15 + beverage.cost();
}
}
Whip.java
//奶泡(配料)
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
然后写一个简单的main函数:
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out
.println(beverage2.getDescription() + " $" + beverage2.cost());
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage2);
beverage3 = new Mocha(beverage2);
beverage3 = new Whip(beverage2);
System.out
.println(beverage3.getDescription() + " $" + beverage3.cost());
}