大家好,我是小菜,一个渴望在互联网行业做到蔡不菜的小菜。可柔可刚,点赞则柔,白嫖则刚!死鬼~看完记得给我来个三连哦!
本文主要介绍
软件设计模式中的行为型模式
如有需要,可以参考 如有帮助,不忘 点赞 ❥ 微信公众号已开启,小菜良记,没关注的同学们记得关注哦!
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
模板简单来说抽取一部分逻辑,其他具体实现可以直接用。在开发中经常会遇到设计一个系统时,我们会抽取一个抽象类,而有许多个不同的子实现类,但是子实现类中有部分算法逻辑是固定的,那我们只需要在父类中定义好这些逻辑,然后在不同的实现类中扩展额外的算法逻辑即可。
因此我们可以得出一个小结论:模板方法模式是基于继承的
我们顺势根据 UML图 总结下 模板方法模式 中存在的几种角色:
接下来我们用个简单的例子来了解一下 模板方法模式 的使用方法:
以上我们以炒菜为例,其中炒菜的步骤是固定的,倒油、下菜、下调料、翻炒
,然后其中基本代码由子类来具体实现。
我们可以发现,模板方法模式是通过父类建立框架,子类再重写父类的部分方法之后,产生不同的效果,通过修改子类可以影响到父类行为的结果,那么这种模式又有啥优缺点呢!如下:
优点:
缺点:
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
生活中策略模式随处可见,出行方式的选择:
乃至开发工具的选择:
该模式的 UML 图也较为简单:
由图可知存在的角色如下:
举个生活中的例子如下:
某大型商场开展周年庆活动,根据商家的不同等级(金牌会员,银牌会员,铜牌会员)做出不同的活动策略,活动 UML 图如下:
码示如下:
通过以下代码我们简单的实现了策略模式,其中的优缺点我们也有必要知道:
优点:
缺点:
讲一个请求封装成为一个对象,使发出请求的责任和执行请求的责任分隔开,这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理
看到这张图我们就会想到我们平时去餐店吃饭的场景:我们需要把我们要点的餐写在订单上,然后服务员拿着订单转去柜台,通知厨师需要出的菜,这个时候厨师根据订单上 的内容将食物备好,最后顾客满意的吃上食物。
这个过程便是利用了命令模式,将订单作为一个请求封装成对象,将服务员和厨师之间的责任隔开,两者只需要通过订单进行沟通,方便将命令模式进行存储、传递、调用、增加与管理。
我们顺势得出命令模式的 UML 图 和 角色:
有了以上基本的了解,我们就这上面点餐的例子,总结一下点餐的 UML 图
码示如下:
看完了示例代码,我们再来盘一盘它的优缺点:
优点:
缺点:
责任链模式又称为职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
现实中我们最经常经历的便是请假,不管是学校请假或是公司请假,我们都得提交请假申请。但是根据请假天数的不同,处理的责任人也不同。在公司请假,可以审批的责任人可能有部门负责人,区域负责人甚至总负责人。但是每个负责人可以批准的天数不同,如果没有用到责任链模式的设计,我们请假就必须自己去找相应的负责人,而我们如果找到部门负责人还比较方便,如果请的天数较多,我们还得去找区域负责人以及总负责人,这是一件十分麻烦的事情。那我们就来了解一下责任链模式到底是怎样运行的。
责任链模式 UML 图 与角色关系如下:
我们根据上面那个例子,总结一下。图示如下:
码示如下:
老规矩盘下 责任链模式 的优缺点:
优点:
非常显著的优点就是将请求和处理分开。请求者不用知道是谁处理的,处理者不用知道请求的全貌。两者解耦,提高系统灵活性
缺点:
对有状态的对象,把复杂的 “判断逻辑” 提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为
状态是我们生活中用到比较多的词汇之一。万物皆有状态,不同时间不同地点不同状态。我们可以从精神饱满的状态到昏昏欲睡的状态。
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
。状态模式 主要解决的问题就是当控制一个对象状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到标识不同状态的一系列类当中。
状态模式 中存在的角色有:
我们如果在网上进行购物的话就会产生订单,不同状态下会有不同的行为,订单状态可分为 加购状态、付款状态、收货状态、评价状态。在整个订单流转的过程中,由不同的事件行为可导致它状态的变更:
一般写法我们是这样的:
public class OrderServiceImpl implements OrderService {
private OrderMapper orderMapper;
public void process(Long orderId) {
Order order = orderDao.findById(orderId);
if (order.getStatus() == OrderStatus.WAIT_PAY) {
// 待支付,则进行支付
} else if (order.getStatus() == OrderStatus.PAYING) {
// 支付中,则进行相应提示
} else if (order.getStatus() == OrderStauts.PART_PAID) {
// 部分支付,则进行相应处理
} else {
// 其他状态进行对应处理
}
}
}
如果遇到状态比较多的情况,用 if else
处理起来比较乱,那么我们可以用状态模式来改进试下,UML 图如下:
码示如下:
抽象状态角色:
具体状态角色 - 加购状态:
具体状态角色 - 付款状态:
具体状态角色 - 收货状态:
具体状态角色 - 评价状态:
上下文角色:
以上便是简单的实现了 状态模式,那我们盘一下它的优缺点
优点:
缺点:
观察者模式又称为 发布-订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
观察者模式相当于一个第三者,比如我们在学校自习的时候,有些人聊天,有些人睡觉,这个时候为了不让老师抓到,我们都会找一个 "放风" 的同学,如果老师来的话就会及时发出通知。
观察者模式 的 UML 图是这样的:
我们可以清晰的看出其中存在的几种角色:
接下来我们根据以上学生的例子用 观察者模式 实现一下:
这样子就简单地实现了 观察者模式。但是观察者模式也存在不足之处,我们想说说它的好:
优点:
缺点:
中介模式又称为 调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互
一般来说,同事对象之间的关系是比较复杂的,多个同事对象之间相互关联的时候,他们之间的关系就会呈现为复杂的网状结构,这是一种过渡耦合的架构,,既不利于类的复用,也不稳定,加入其中一个对象发生变化,其他对象也会相应收到影响。
因此这个时候就引入了中介者模式,那这个时候同事对象之间的关系就变成了星型结构,任何一个类的变动,只会影响到类本身以及中介者,这样就减少了系统的耦合。
中介者模式的 UML 图 和 角色 如下:
中介者模式最经典的案例还是 房产中介
。现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。代码实现如下:
通过 中介者模式,房东与租户可以不用直接交互,较少了类与类之间的复杂关系,那么这种模式又有什么优缺点呢?如下:
优点:
缺点:
提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示
这里说的 迭代器模式 与我们平时在集合中用到的 迭代器 是一回事,我们平时是这样这样使用的:
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); //list.iterator()方法返回Iterator接口的子实现类对象
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
我们平时用的溜溜的,但是具体内部实现你是否有所了解,我们老样子来看下迭代器模式中的 UML 图 和 角色:
然后我们用代码来了解一下迭代器的内部实现:
通过以上方式我们简单的实现了 迭代器 的实现,以下说下它的优缺点
优点:
缺点:
增加了类的个数,这在一定程度上增加了系统的复杂性
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作
简单来说就是想要为一个对象增强新的行为,且不封装具体的实现,那么就可以用访问者模式。UML 图如下:
其中存在的角色有:
Element
)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲是与元素类的个数(Element
)的实现类个数是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变accept
),意义在于每一个元素都可以被访问者访问Element
),并且可以迭代这些元素,供访问者访问我们假设一个场景,动物园的动物需要饲养员喂养,部分动物(老虎,狮子...)游客也可以喂养,然后我们给这些角色分下类:
代码实现如下:
抽象访问者
具体访问者
抽象元素 & 具体元素
对象结构
测试类
输出
饲养员喂养老虎
老虎受到了饲养员喂养
饲养员喂养狮子
狮子受到了饲养员的喂养
=========
游客喂养老虎
老虎受到了游客喂养
游客喂养狮子
狮子受到了游客的喂养
通过 访问者模式,我们可以很清楚的实现这个需求,这个模式的优缺点如下:
优点:
缺点:
备忘录模式又称为 快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态
其实这个模式最经典的案例便是 ctrl+z
的功能,在我们编辑文本的时候,撤销操作便是。备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
UML结构图如下:
有玩过游戏的同学,应该都知道一个称为 存档 的功能,存档的目的在于在游戏进行到一个不理想的程度时,可以恢复到之前巅峰的状态。让我们就用代码来简单模拟一下这个游戏的场景。首先游戏角色肯定会有 生命值
的属性,我们简单整理一下 UML 图
然后我们用代码来表示一下:
通过 备忘录模式 我们就可以实现无线重试的机会,让我们来理下这种模式的优缺点:
优点:
缺点:
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子
解释器这个名词小伙伴们应该不会很陌生,在编译原理中,一个算术表达式可通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。
计算器我们肯定都有用过,如果让你实现一个简单的加法运算,我们的第一个想法应该是这样写的:
public static int plus(Integer ... args) {
int sum = 0;
for (Integer i : args) {
sum += i;
}
return sum;
}
但是这种适合于形式比较单一,有限的场景,如果形式变化比较多,那么这种就不符合要求。
那么现在我们就需要一种翻译识别机器,能够解析由数字、- 、+
构成的运算序列。我们可以把数字和运算符都看作节点, 然后对逐个节点进行读取解析运算,这种就是 解释器模式 的思维。
然后我们来看下解释器模式的 UML 图:
interpret()
那我们接下来就用 解释器模式 来简单实现一下 加减法
的逻辑:
UML 图
:
代码如下:
表达式角色:
上下文环境:
测试类:
通过 解释器模式 我们可以很清晰的看出代码的逻辑,实现了以上功能。总结下这种模式的优缺点:
优点:
缺点:
软件设计模式到这篇就结束啦,一共有 22
个设计模式,量多需消化,小伙伴们好好看哦!路漫漫小菜与你一同求索。
看完不赞,都是坏蛋
今天的你多努力一点,明天的你就能少说一句求人的话! 我是小菜,一个和你一起学习的男人。
?
微信公众号已开启,小菜良记,没关注的同学们记得关注哦!
- END -