设计模式-策略、装饰、代理

前言

本文为datawhale2022年12月组队学习《大话设计模式》task2打卡学习,内容主要以官方所提供为主,会加入一些个人的学习心得。
【教程地址】https://github.com/datawhalechina/sweetalk-design-pattern

一、策略模式

1.1 基本定义

是指定义一个算法家族,使得家族内的不同算法都遵从算法家族的接口及方法规范,从而可以实现算法间互相替换,且不会影响到使用算法的客户。
简单来说,就是提前准备好一组算法,将每一个算法的实现封装起来,在使用时进行互换。

1.2 问题引入

实现一个商场收银软件程序,营业员可以通过输入客户所有购买商品的单价和数量,程序自动计算出总金额。同时,商场有时会有打折活动(如商品打7折),或满减促销活动(如商品满300-100),程序应能考虑这些活动的情形,在尽量减少重复代码的前提下,实现正确的金额计算。

1.2.1 问题分析

对于打7折,打8折,满300-100,满700-200等商场的促销活动,其整体的业务逻辑是类似的,而且随时可以相互替换,符合策略模式的应用场景。

1.2.2 问题解决

  1. 首先创建抽象的算法类,作为所有促销活动算法的抽象类,同时定义所有支持算法的公共接口,定义方法用于得到结果;
  2. 创建具体的促销算法类,等,继承于抽象算法类,覆写实现具体的促销算法;
  3. 创建上下文类,维护对算法对象的引用,使用时根据用户输入,传入一个具体的促销算法类来配置。

1.2.3 代码实现

这里不再多余进行复制粘贴了,直接放上datawhale所给的的源码链接:
策略模式Java实现
策略模式python实现

1.3 与简单工厂模式的区别

其实单看代码,直观给人感觉高度相似,没有什么区别,但是如果深入分析一下,其实还是有许多不同。

  • 首先看这两种模式的实现类:

简单工厂模式 :

策略模式 :

  • 再来看后面的调用:

简单工厂模式 :

策略模式 :

从代码中可以看到:
工厂模式主要是返回的接口实现类的实例化对象,最后返回的结果是接口实现类中的方法,而策略模式是在实例化的过程中将策略一并创建完。
对于不同的业务,策略模式需要在上下文类中实现,而工厂模式则是需要实例化后再对不同的功能进行拼接。
相对来说,策略模式注重的是过程,而工厂模式只关注最后的结果。

二、装饰模式

2.1 基本定义

是指创建一个装饰类,来包装原有的类,从而实现动态地向一个现有的对象添加一些额外的职责,同时不改变其原有的结构。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

2.2 问题引入

实现人的自由穿搭,要求避免穿每一件衣服的过程直接在客户端实现,同时又保留服装搭配的灵活性。

2.2.1 问题分析

对于人的穿搭问题,衣服、鞋子、领带、披风等服饰都可以理解为对人的装饰。可以先定义一个Person类表示人,然后再定义具体的服饰类实现对Person类进行服装装饰,装扮完再统一显示

2.2.2 问题解决

  1. 创建抽象的接口类,定义给对象动态添加职责的公共接口(在此例中,由于具体的接口只有一个,所以该步也可省略);
  2. 创建具体的接口(Concrete Component),继承于抽象接口类,同时:
    • 定义方法用于显示装扮结果;
  3. 创建抽象的装饰类(Decorator),继承于接口类(一般来说继承于抽象接口类,由于此例只有一个接口,故继承于具体接口类),同时:
    • 定义方法用于进行装扮过程;
    • 覆写具体装扮结果的显示;
  4. 创建系列具体的服饰类(Concrete Decorator),如,等,继承于抽象装饰类,实现具体的装饰对象,同时:
    • 覆写具体装扮结果的显示。

2.2.3 代码实现

这里依然不再多余进行复制粘贴了,直接源码链接:
装饰模式Java实现
装饰模式python实现

2.3 优缺点

2.3.1 优点

  • 装饰类和被装饰类可以独立发展,而不会相互耦合。它有效地把类的核心职责和装饰功能分开了
  • 装饰模式是继承关系的一个替代方案,无需创建新子类即可实现对类功能的动态扩展
  • 装饰模式可以动态地扩展一个实现类的功能

2.3.2 缺点

  • 各装饰层的代码相对冗余,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像
  • 在封装器栈中删除特定封装器比较困难
  • 较难实现行为不受到先后顺序影响的装饰

三、代理模式

3.1 基本定义

是指实现一个类代表另一个类的功能,为其他对象提供一种代理以控制对这个对象的访问。

3.2 问题引入

隔壁班的卓贾易想追求娇娇,但是他自己不好意思,就委托和娇娇同班的戴励帮助他。卓贾易给娇娇先后买了芭比娃娃、花、巧克力,饼委托戴励送给娇娇,却没想给娇娇和戴励创造了相处的机会。娇娇和戴励通过接触互生情愫,最后在一起了。卓贾易自然是很生气,一番追求却为他人做了嫁衣。但细细想来,虽说一直是卓贾易给娇娇买的礼物,但娇娇自始至终都是从戴励手里拿到的礼物,她并未接触过送礼之人——卓贾易。
这真是个悲伤的故事…

3.2.1 问题分析

用程序来描述这一个故事,关键之处在于准确描述卓贾易、戴励及娇娇三者之间的行动关系:娇并不认识卓贾易,礼物是卓贾易买的,戴励并没有礼物直接送给娇娇。
这一问题中有三个类型的角色,追求者(卓贾易),代理(戴励)和被追求者(娇娇)。他们三者间的关系满足,追求者(卓贾易)委托代理(戴励),通过代理(戴励)给被追求者(娇娇)送礼物,而被追求者(娇娇)只与代理(戴励)有接触。
若使用代理模式描述,即代理(戴励)代表了追求者(卓贾易)的追求(赠送礼物)的功能,被追求者(娇娇)仅与代理(戴励)接触便收到了礼物。这样就实现了他们三人关系的准确描述。

3.2.2 问题解决

  1. 创建送礼物的抽象类,定义追求者和代理的共用接口:
    • 送玩具方法;
    • 送花方法;
    • 送巧克力方法。
  2. 创建追求者,定义需要代理的真正实体,继承于抽象类:
    • 覆写类初始化方法,记录被追求者姓名;
    • 覆写送玩具、送花、送巧克力方法,具体送礼操作。
  3. 创建代理,保存追求者实体的一个引用,使得代理可以访问实体,继承于抽象类,实现对实体的替代:
    • 覆写类初始化方法,初始化的同时初始化一个追求者对象;
    • 覆写送玩具、送花、送巧克力方法,在每一个送礼方法下调用追求者的具体送礼操作。

3.2.3 代码实现

源码链接:
代理模式Java实现
代理模式python实现

3.3 优缺点

3.3.1 优点

  • 引入代理后,职责清晰;
  • 引入代理后,可扩展多种用途,如:
    • 远程代理可以隐藏一个对象存在于不同地址空间的事实。
    • 虚拟代理可以存放实例化时间很长的真实对象。
  • 符合“开放封闭原则”,无需对服务器或客户端进行修改就创建新的代理。

3.3.2 缺点

  • 实现代理模式需要额外的工作(有些代理模式的实现非常复杂),代码可能变得复杂;
  • 由于在客户与真实目标之间增加了代理对象,因此会造成请求的处理速度变慢,服务响应可能产生会延迟。

参考

[1] datawhale大话设计模式教程云 – GitHub
[2] 个人理解简单工厂模式和策略模式的区别
[3] 设计模式——装饰模式(Decorator)
[4] 10分钟看懂动态代理设计模式

来源:不让人放心

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年11月15日
下一篇 2022年11月15日

相关推荐