带你读《2022技术人的百宝黑皮书》——浅析设计模式3 —— 装饰者模式(2)

简介: 带你读《2022技术人的百宝黑皮书》——浅析设计模式3 —— 装饰者模式

带你读《2022技术人的百宝黑皮书》——浅析设计模式3 —— 装饰者模式(1)

https://developer.aliyun.com/article/1262382?groupCode=taobaotech



基本概念

装饰者模式的核心思想是通过创建一个装饰对象(即装饰者),动态扩展目标对象的功能,并且不会改变目标对象 的结构,提供了一种比继承更灵活的替代方案。需要注意的是,装饰对象要与目标对象实现相同的接口,或继承相 同的抽象类;另外装饰对象需要持有目标对象的引用作为成员变量,而具体的赋能任务往往通过带参构造方法来完 成。


下面继续从模式结构和使用步骤两个层面,简单阐述装饰者模式的基本概念。


结构


装饰者模式包含四种类,分别是抽象构件类、具体构件类、抽象装饰者类、具体装饰者类,它们各自负责完成特定 任务,并且相互之间存在紧密联系。

image.png


image.png


使用

有了上述的基本概念,我们将装饰者模式的使用步骤概括为:

1. step1:创建抽象构件类,定义目标对象的抽象类、将要扩展的功能定义成抽象方法;

2. step2:创建具体构件类,定义目标对象的实现类,实现抽象构件中声明的抽象方法;

3. step3:创建抽象装饰者类,维护一个指向抽象构件的引用,并传入构造函数以调用具体构件的实现方法,给具  体构件增加功能;

4. step4:创建具体装饰者类,可以调用抽象装饰者类中定义的方法,并定义若干个新的方法,扩展目标对象的功能。


使用示例

我们在淘宝上购物时,经常会遇到很多平台和商家的优惠活动:满减、聚划算站内的百亿补贴券、店铺折扣等等。 那么在商品自身原价的基础上,叠加了多种优惠活动后,后台应该怎样计算最终的下单结算金额呢?下面就以这种 优惠叠加结算的场景为例,简单分析装饰者模式如何使用。


代码实现

// 定义抽象构件:抽象商品
public interface ItemComponent {
 // 商品价格
 public double checkoutPrice();
}
// 定义具体构件:具体商品
public class ConcreteItemCompoment implements ItemComponent {
 // 原价
 @Override
 public double checkoutPrice() {
 return 200.0;
 }
}
// 定义抽象装饰者:创建传参(抽象构件)构造方法,以便给具体构件增加功能
public abstract class ItemAbsatractDecorator implements ItemComponent {
 protected ItemComponent itemComponent;
 public ItemAbsatractDecorator(ItemComponent myItem) {
 this.itemComponent = myItem;
 }
 @Overrid
 public double checkoutPrice() {
 return this.itemComponent.checkoutPrice();
 }
}
// 定义具体装饰者A:增加店铺折扣八折
public class ShopDiscountDecorator extends ItemAbsatractDecorator {
 public ShopDiscountDecorator(ItemComponent myItem) {
 super(myItem);
 }
  @Override
 public double checkoutPrice() {
 return 0.8 * super.checkoutPrice();
 }
} 
// 定义具体装饰者B:增加满200减20功能,此处忽略判断逻辑
public class FullReductionDecorator extends ItemAbsatractDecorator {
 public FullReductionDecorator(ItemComponent myItem) {
 super(myItem);
 }
  @Override
 public double checkoutPrice() {
 return super.checkoutPrice() - 20;
 }
}
// 定义具体装饰者C:增加百亿补贴券50
public class BybtCouponDecorator extends ItemAbsatractDecorator {
 public BybtCouponDecorator(ItemComponent myItem) {
 super(myItem);
 }
 @Override
 public double checkoutPrice() {
  return super.checkoutPrice() - 50;
 }
}
//客户端调用
public class userPayForItem() {
 public static void main(String[] args) {
 ItemCompoment item = new ConcreteItemCompoment();
 System.out.println("宝贝原价:" + item.checkoutPrice() + " 元");
 item = new ShopDiscountDecorator(item);
 System.out.println("使用店铺折扣后需支付:" + item.checkoutPrice() + " 元");
 item = new FullReductionDecorator(item);
 System.out.println("使用满200减20后需支付:" + item.checkoutPrice() + " 元");
 item = new BybtCouponDecorator(item);
 System.out.println("使用百亿补贴券后需支付:" + item.checkoutPrice() + " 元");
 }
} 


结果输出

宝贝原价:200.0 元
使用店铺折扣后需支付:160.0 元
使用满200减20后需支付:140.0 元
使用百亿补贴券后需支付:90.0 元


UML图


image.png


比较分析  


VS 继承

装饰者模式和继承关系都是要对目标类进行功能扩展,但装饰模式可以提供比继承更多的灵活性:继承是静态添加 功能,在系统运行前就会确定下来;装饰者模式是动态添加、删除功能。


比如,一个对象需要具备 10 种功能,但客户端可能要求分阶段使用对象功能:在第一阶段只执行第 1-8 项功能, 第二阶段执行第 3-10 项功能,这种场景下只需先定义好第 3-8 项功能方法。在程序运行的第一个阶段,使用具体 装饰者 A 添加 1、2 功能;在第二个运行阶段,使用具体装饰者 B 添加 9、10 功能。而继承关系难以实现这种需 求,它必须在编译期就定义好要使用的功能。  


VS 代理模式


装饰者模式常常被拿来和代理模式比较,两者都要实现目标类的相同接口、声明一个目标对象,并且都可以在不修 改目标类的前提下进行方法扩展,整体设计思路非常相似。那么两者的区别是什么呢?


首先,装饰者模式的重点在于增强目标对象功能,而代理模式的重点在于保护和隐藏目标对象。其中,装饰者模式 需要客户端明确知道目标类,才能对其功能进行增强;代理模式要求客户端对目标类进行透明访问,借助代理类来 完成相关控制功能(如日志记录、缓存设置等),隐藏目标类的具体信息。可见,代理类与目标类的关系往往在编 译时就确定下来,而装饰者类在运行时动态构造而成。


其次,两者获取目标类的方式不同。装饰者模式是将目标对象作为参数传给构造方法,而代理模式是通过在代理类 中创建目标对象的一个实例。


最后,通过上述示例可发现,装饰者模式会使用一系列具体装饰者类来增强目标对象的功能,产生了一种连续、叠 加的效应;而代理模式是在代理类中一次性为目标对象添加功能。  


VS 适配器模式


两者都属于包装式行为,即当一个类不能满足需求时,创建辅助类进行包装以满足变化的需求。但是装饰者模式的 装饰者类和被装饰类都要实现相同接口,或者装饰类是被装饰类的子类;而适配器模式中,适配器和被适配的类可 以有不同接口,并且可能会有部分接口重合。


带你读《2022技术人的百宝黑皮书》——浅析设计模式3 —— 装饰者模式(3)

https://developer.aliyun.com/article/1262380?groupCode=taobaotech

相关文章
|
6月前
|
设计模式 前端开发 JavaScript
【JavaScript 技术专栏】JavaScript 设计模式与实战应用
【4月更文挑战第30天】本文探讨JavaScript设计模式在提升开发效率和代码质量中的关键作用。涵盖单例、工厂、观察者、装饰器和策略模式,并通过实例阐述其在全局状态管理、复杂对象创建、实时数据更新、功能扩展和算法切换的应用。理解并运用这些模式能帮助开发者应对复杂项目,提升前端开发能力。
84 0
|
16天前
|
设计模式 Java Kotlin
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
|
3月前
|
设计模式 物联网 Android开发
移动应用与系统:探索未来技术的融合之路后端开发中的设计模式探索
【8月更文挑战第21天】随着科技的飞速发展,移动应用和操作系统已经成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用开发和移动操作系统的相关话题,包括它们的历史、现状以及未来的发展趋势。我们将从移动应用的开发环境、编程语言和工具等方面进行详细的分析,同时也会讨论移动操作系统的特点、优势以及面临的挑战。最后,我们将展望移动应用与系统在未来技术融合中的可能方向和机遇。
132 58
|
30天前
|
设计模式 Java Kotlin
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
41 0
|
1月前
|
设计模式 Java Kotlin
Kotlin 学习笔记- 改良设计模式 - 装饰者模式
Kotlin 学习笔记- 改良设计模式 - 装饰者模式
26 0
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
22 0
|
4月前
|
设计模式 安全 Java
技术成神之路:设计模式(一)单例模式
【7月更文挑战第3天】技术成神之路:设计模式(一)单例模式
42 1
|
5月前
|
设计模式 Java API
程序技术好文:设计模式:装饰者模式
程序技术好文:设计模式:装饰者模式
26 0
|
5月前
|
设计模式 网络协议 Java
技术笔记:Reactor设计模式
技术笔记:Reactor设计模式
63 0
|
5月前
|
设计模式 算法 索引
程序技术好文:设计模式之美:Builder(生成器)
程序技术好文:设计模式之美:Builder(生成器)