1. 模式简介
在不改变原有对象的基础之上,将新功能附加到原有对象上,提供了比继承更有弹性的解决方案(扩展原有对象的功能),属于结构型设计模式。
2. 示例代码
这回咱们就土豪一把,模拟购买 2019 款 MacBook Pro 16 寸,来演示装饰者模式的逻辑。
- MacBook Pro 的基础信息
/**
* <p>
* 苹果笔记本
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 16:51
*/
public interface MacBookPro {
/**
* 套餐名称
*
* @return 套餐名称
*/
String getComboName();
/**
* 硬盘
*
* @return 硬盘
*/
String getHardDisk();
/**
* 内存
*
* @return 内存
*/
String getMemory();
/**
* 价格
*
* @return 价格
*/
Double getPrice();
}
- 定义我们的套餐装饰器
/**
* <p>
* 套餐 - 装饰器
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 17:08
*/
@AllArgsConstructor
public abstract class ComboDecorator implements MacBookPro {
private MacBookPro macBookPro;
/**
* 套餐名称
*
* @return 套餐名称
*/
@Override
public String getComboName() {
return this.macBookPro.getComboName();
}
/**
* 硬盘
*
* @return 硬盘
*/
@Override
public String getHardDisk() {
return this.macBookPro.getHardDisk();
}
/**
* 内存
*
* @return 内存
*/
@Override
public String getMemory() {
return this.macBookPro.getMemory();
}
/**
* 价格
*
* @return 价格
*/
@Override
public Double getPrice() {
return this.macBookPro.getPrice();
}
}
- 基础套餐
/**
* <p>
* 苹果笔记本基础套餐
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 16:52
*/
public class BaseMacBookProCombo implements MacBookPro {
/**
* 套餐名称
*
* @return 套餐名称
*/
@Override
public String getComboName() {
return "基础套餐";
}
/**
* 硬盘
*
* @return 硬盘
*/
@Override
public String getHardDisk() {
return "1T 固态硬盘";
}
/**
* 内存
*
* @return 内存
*/
@Override
public String getMemory() {
return "16GB 2666MHz DDR4 内存";
}
/**
* 价格
*
* @return 价格
*/
@Override
public Double getPrice() {
return 22199d;
}
}
- 16G内存套餐
/**
* <p>
* 内存套餐
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 17:17
*/
public class MemoryCombo extends ComboDecorator {
public MemoryCombo(MacBookPro macBookPro) {
super(macBookPro);
}
/**
* 套餐名称
*
* @return 套餐名称
*/
@Override
public String getComboName() {
return super.getComboName() + " + 升级内存";
}
/**
* 内存
*
* @return 内存
*/
@Override
public String getMemory() {
return super.getMemory() + " + 16G 内存";
}
/**
* 价格
*
* @return 价格
*/
@Override
public Double getPrice() {
return super.getPrice() + 2936;
}
}
- 1T硬盘套餐
/**
* <p>
* 硬盘套餐
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 17:15
*/
public class HardDiskCombo extends ComboDecorator {
public HardDiskCombo(MacBookPro macBookPro) {
super(macBookPro);
}
/**
* 套餐名称
*
* @return 套餐名称
*/
@Override
public String getComboName() {
return super.getComboName() + " + 升级硬盘";
}
/**
* 硬盘
*
* @return 硬盘
*/
@Override
public String getHardDisk() {
return super.getHardDisk() + " + 1TB 固态硬盘";
}
/**
* 价格
*
* @return 价格
*/
@Override
public Double getPrice() {
return super.getPrice() + 2936;
}
}
- 测试类,我们需要购买一台 2T 固态硬盘 64G 内存的 MacBook Pro
/**
* <p>
* 装饰者模式 - 测试类
* </p>
*
* @author yangkai.shen
* @date Created in 2019/12/13 17:19
*/
public class PatternTest {
public static void main(String[] args) {
// MacBookPro 基础套餐
MacBookPro macBookPro = new BaseMacBookProCombo();
printInfo(macBookPro);
// 升级内存 16G -> 64G
macBookPro = new MemoryCombo(macBookPro);
macBookPro = new MemoryCombo(macBookPro);
macBookPro = new MemoryCombo(macBookPro);
printInfo(macBookPro);
// 升级硬盘 1T -> 2T
macBookPro = new HardDiskCombo(macBookPro);
printInfo(macBookPro);
}
private static void printInfo(MacBookPro macBookPro) {
System.out.println("当前套餐: " + macBookPro.getComboName());
System.out.println("内存: " + macBookPro.getMemory());
System.out.println("硬盘: " + macBookPro.getHardDisk());
System.out.println("总价为: " + macBookPro.getPrice() + " 元");
System.out.println("\n======================================\n");
}
}
- 测试结果
当前套餐: 基础套餐
内存: 16GB 2666MHz DDR4 内存
硬盘: 1T 固态硬盘
总价为: 22199.0 元
======================================
当前套餐: 基础套餐 + 升级内存 + 升级内存 + 升级内存
内存: 16GB 2666MHz DDR4 内存 + 16G 内存 + 16G 内存 + 16G 内存
硬盘: 1T 固态硬盘
总价为: 31007.0 元
======================================
当前套餐: 基础套餐 + 升级内存 + 升级内存 + 升级内存 + 升级硬盘
内存: 16GB 2666MHz DDR4 内存 + 16G 内存 + 16G 内存 + 16G 内存
硬盘: 1T 固态硬盘 + 1TB 固态硬盘
总价为: 33943.0 元
======================================
3. UML 图例
4. 应用
// JDK 中的 IO 类
// BufferedReader、InputStream、OutputStream
// Spring 中处理事务缓存 TransactionAwareCacheDecorator
// Spring MVC 中对 Header 的处理 HttpHeadResponseDecorator
5. 场景
- 用于扩展一个类的功能。
- 给一个类添加附加职责。
- 动态的给一个对象添加功能,这些功能可以再动态的撤销。
6. 优缺点
优点: 1、装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象 扩展功能,即插即用。 2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。 3、装饰者完全遵守开闭原则。
缺点: 1、会出现更多的代码,更多的类,增加程序复杂性。 2、动态装饰时,多层装饰时会更复杂。