目录
一、简介
装饰器模式(Decorator
Pattern) :允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
二、范例:咖啡店
刚开始时,咖啡店的程序设计是:
- 一个咖啡饮料的父类 Beverage,抽象类,店里的所有饮料都必须继承此父类
- 不同种类的咖啡饮料都是一个类(都需要继承 Beverage类)
带来的问题:
购买咖啡饮料时,客户可以要求加入不同中类的配料,如:摩卡、奶泡…
此时的咖啡店的程序设计是:
三、优化方案:实例变量和继承
Beverage类优化:
Beverage类中新增表示各种调料的实例变量
咖啡饮料类:
带来的问题:
- 调料价格的改变需要修改代码
- 新增调料需要改变Beverage类的 cost()方法
- …
设计原则:类应该对扩展开放,对修改关闭
四、优化方案:装饰者模式
以咖啡饮料为主体,然后在运行时以调料来装饰(decorate)咖啡饮料。比如,如果顾客想要摩卡和奶泡深培咖啡,那么,做法是:
- 获取一个深培咖啡(DarkRoast)对象
- 以摩卡(Mocha)调料对象来装饰它
- 以奶泡(Whip)调料对象来装饰它
- 调用cost()方法,并依赖委托(delegate)将调料的价格加上去
4.1、做法图解:
- 获取一个深培咖啡(DarkRoast)对象
- 顾客想要摩卡(Mocha)调料,所以建立一个Mocha对象,并用它将DarkRoast对象包(wrap)起来
- 顾客想要奶泡(Whip),所以建立一个Whip装饰者,并将它Mocha对象包起来
- 计算总价钱,调用最外层的装饰者(Whip)的cost()方法就可以计算出总价钱。Whip的cost()方法会委托它装饰的对象,即Mocha,计算出价钱,然后再加上奶泡的价钱
4.2、代码实现
Beverage类:
package com.kgf.headFirst.decorator;
/**
* 咖啡饮料父类
* @author kgf
* @date 2023/6/11 22:19
*/
public abstract class Beverage {
String description = "咖啡饮料父类";
public String getDescription() {
return description;
}
public abstract double cost();
}
咖啡饮料类:
package com.kgf.headFirst.decorator;
/**
* 咖啡饮料类:
* @author kgf
* @date 2023/6/11 22:20
*/
public class Espresso extends Beverage{
public Espresso() {
description = "浓缩咖啡";
}
@Override
public double cost() {
return 1.99;
}
}
package com.kgf.headFirst.decorator;
/**
* 混搭咖啡
* @author kgf
* @date 2023/6/11 22:21
*/
public class HouseBlend extends Beverage{
public HouseBlend() {
description = "混搭咖啡";
}
@Override
public double cost() {
return 1.5;
}
}
调料类:
package com.kgf.headFirst.decorator;
/**
* 调料类
* @author kgf
* @date 2023/6/11 22:23
*/
public abstract class CondimentDecorate extends Beverage{
@Override
public abstract String getDescription();
}
package com.kgf.headFirst.decorator;
/**
* 摩卡
* @author kgf
* @date 2023/6/11 22:24
*/
public class Mocha extends CondimentDecorate{
Beverage beverage;
/***
* 让Mocha对象能够引用一个Beverage
* 用一个实例变量记录饮料,即被装饰者
* 让被装饰者(饮料)被记录到实例变量中(此处做法是:把饮料作为构造器的参数,再由构造器将此饮料记录在实例变量中)
* @param beverage
*/
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
// 计算带Mocha的咖啡饮料的价钱:Mocha的价钱 + 咖啡饮料的价钱
return 0.5 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",摩卡";
}
}
package com.kgf.headFirst.decorator;
/**
* 调料:奶泡
* @author kgf
* @date 2023/6/11 22:26
*/
public class Whip extends CondimentDecorate{
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return 0.8 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",奶泡";
}
}
测试:
package com.kgf.headFirst.decorator;
/**
* @author kgf
* @date 2023/6/11 22:33
*/
public class Test {
public static void main(String[] args) {
Beverage espresso = new Espresso();
//咖啡饮料:浓缩咖啡,价钱:1.99
System.out.println("咖啡饮料:" + espresso.getDescription() + "," + "价钱:" + espresso.cost());
Beverage houseBlend = new HouseBlend();
// 加摩卡
houseBlend = new Mocha(houseBlend);
// 加奶泡
houseBlend = new Whip(houseBlend);
//咖啡饮料:混搭咖啡,摩卡,奶泡,价钱:2.8
System.out.println("咖啡饮料:" + houseBlend.getDescription() + "," + "价钱:" + houseBlend.cost());
}
}
总结:
五、Java中的装饰者模式
IO流API: