设计模式开篇

首先应该对要讨论的设计模式主题进行约束,是面向对象编程的设计模式,针对于非面向对象编程,如函数式编程、过程式编程,也有相应的设计模式。

明确了是面向对象编程,那么所有的设计套路都是基于面向对象编程的特性,封装、抽象、继承、多态四大特性就是设计模式的基础,各种模式都是利用了这些基础能力来巧妙设计的,如果没有编程语言自身的能力支持,就谈不上设计模式了。

因此,这四大特性应该真正做到理解,而非死记硬背,理解之后,后续讲到每一种设计思路时,才会有清晰的脉络,模式不是被突发的设计出来的,而是经过经验演进而来。

封装,将同一类的属性、方法统一装在一个类中,强调聚类效果。
抽象,在具体类别上再设计一层,能够更高的抽象,定义通用的接口或抽象类,隐藏具体的实现细节,提供更通用的视图。
继承,通过类的层次化结构实现代码复用,子类可以扩展或修改父类的行为,减少代码重复。
多态,通过父类的接口调用子类的具体实现,使得代码能够以一种通用的方式处理不同的对象,提高代码的通用性和灵活性。

这些特性共同构成了面向对象编程的核心,是设计模式的基石。

上图中,可以看到是整个设计模式的一个最小结构,其他的模式都是在此基础之上,进行变化,只是各个模式的目的不同,记住这句话,目的不同,目的不同,因此在学习设计模式时,明确了每个模式的目的是什么,是为了解决什么问题,就能够很自然的实际使用中应用上了。而不是死记硬背,到最后发现各个模式的图都很相似,一头雾水。

这四大特性,是整个设计模式的基石,如果开发语言本身没有提供继承能力,没有接口能力,那么面向对象的设计模式就不存在了。

技术的本质是组合与递归,先要清楚最小的原子工具是什么,上层能力都是基于原子能力逐步堆叠上来的。

说完了最基础的基石特性,再来看看设计模式有那么原则,这些原则是前辈们在过往项目中沉淀下来的宝贵经验。

  • 封装变化:将系统中易变的部分独立封装,避免代码的重复修改。
  • 针对接口编程,而非实现:通过接口定义行为,使代码依赖抽象而非具体类,提高灵活性。
  • 多用组合,少用继承:通过对象组合实现功能复用,避免继承导致的类爆炸和僵化。
  • 为交互对象松耦合设计:减少对象间的直接依赖,使系统更灵活、易于扩展。
  • 开发-关闭:类应对扩展开放,对修改关闭。通过组合和装饰动态添加功能。
  • 依赖倒置:高层模块不应依赖低层模块,二者都应依赖抽象。
  • 最少知识:对象应尽量减少与其他对象的交互,只与“朋友”通信。
  • 模式应用:外观模式封装子系统接口,简化客户端调用。
  • 好莱坞原则:高层组件控制流程,低层组件被动响应(“别调用我们,我们会调用你”)。
  • 单一职责:一个类应只有一个引起变化的原因。

太多了不好记忆吧,那就记忆一个简化版,SOLID原则,分别是哪五个单词的首字母,自行查询吧。

其实不需要死记,只要清楚一点,整个设计模式都是在解决一个问题:在需求有修改变动时,能够不对之前的逻辑代码尽量不改动,只做扩展即可,将影响范围降至最小

将变动封装、共性抽象、职责清晰化、依赖最小化,做到后续改动的扩展性,保证已完成的代码少改动,有了这个想法,不经意间,非刻意使用设计模式时,也会写成经典的模式代码。

最后,为什么要学习设计模式呢,一是为了自己实现时能够参考过去好的经验,二是不学习设计模式,别人的代码你看不懂。还记得当初使用和阅读java io库时,多个new连接在一起,是多么的疑惑。

Read more

痛风带来的思考

昨晚一罐冰啤酒下去,睡觉时就感觉脚踝隐隐发作,果然早上起床直接下不来地。跟崴脚的感觉十分相似,无法行走,只能坐在一起上滑动,公司上班也去不了了,呆呆得躺在家里,下午疼痛感加剧,整个心思都在左脚的疼痛上,没有其他任何多余的精力去关注其他事情,而此刻的阳台,乃最美人间四月天,春日的微风吹拂着阳台的花儿,温暖的阳光抛洒下来,一切都如此惬意,而我却无心欣赏。 人在健康时,生活中有好多问题,但人在不健康时,生活中只剩一个问题。 我对这句话的理解更深刻了。人是健忘的,在疫情期间、在手术期间,这种感悟其实已经很深刻了,但是病情好转之后,人还是会被日常的琐碎、工作的烦扰搅乱心绪,没有专注的去享受生活本身的美好。 幸福的秘密在于,去享受我们所拥有的,而不是顽固的去追求所没有拥有的。阳光、草木、微风,都是幸福的玩意儿,应尽情的享受。 再等两天,脚完全恢复好了,身体健健康康后,我要以更轻盈的姿态去生活,不纠结他人的看法,不执着别人的认可,关注自己的能力,享受拥有的生后。 还有一个反省,针对咖啡、酒、烟,

By 李浩

设计模式之命令模式

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,命令模式也支持可撤销的操作。 来解析这个定义: 1. “将一个请求封装为一个对象”,请求原本是一个方法,现在要封装成一个对象,说明要新增类来完成。 2. “可以用不同的请求对客户进行参数化”,说明是将命令对象作为参数进行传递。 3. “队列”说明需要维护命令多个命令的列表队列。 4. “撤销”说明有命令对象有undo撤销方法。 命令模式在设计模式中,算是一个比较不好理解的模式,很重要的原因是不清楚设计意图,不清楚不用这个模式前有何问题,这个模式带了哪些好处,能解决什么问题。 上一篇状态模式中,看到了状态模式抽离的是状态(属性),向上提成状态对象。有了这个基础,再来理解命令模式就相对简单了。命令模式抽离的是行为(方法),向上提成命令对象。 两者都通过“对象化”来解耦和扩展系统,但解决的问题不同: * 状态模式:处理对象内部状态驱动的行为变化。 * 命令模式:处理行为请求的封装与调度。 💡智能家居遥控器,假设我们有一个智能家居遥控器,可以控制 灯(Light) 和

By 李浩

设计模式之状态模式

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。 来解析这个定义: 1. “内部状态”表明对象内部有一个属性来表示状态。 2. “内部状态改变时改变它的行为,对象看起来好像修改了它的类”说明状态改变后对象的行为发生了非常大的变化,不像是同一类的行为。 从目前的分析中似乎无法推导出状态模式的类图结构。 从实际的例子出来,来看看状态模式是如何演进而来。 💡我们有一个文档审批系统,文档有以下状态和转换: 1. 草稿(Draft) → 提交 → 待审批(PendingReview) 2. 待审批 → 批准 → 已发布(Published) 3. 待审批 → 拒绝 → 草稿 4. 已发布 → 撤回 → 草稿 从直觉出发,会使用条件语句实现需求逻辑。 public class Document { private String state = "DRAFT"; // 初始状态为草稿 public void submit(

By 李浩

设计模式之代理模式

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。 解析这个定义: 1. “替身”表明在客户端看来,代理类与被代理类是同一类别,对客户端来说看上去没什么区别,依然能够满足诉求。如此可以看出代理类与被代理类来自同一个超类。 2. “控制对这个对象的访问”,能够控制访问,说明前提是能够访问,才能在访问之前做这个限制,即代理持有对真实对象的引用(或能创建它)。 当然可能会质疑,用继承的方式不是也能完成目标吗,用代理类去继承被代理类,然后重写方法,加入控制逻辑。但这违背了"组合优于继承"原则,代理类与被代理类强耦合。 💡我们要开发一个图片查看器,需求如下: 1. 图片加载开销大(从磁盘或网络加载耗时),希望首次显示时才加载(延迟加载)。 2. 某些图片需要权限校验,只有授权用户才能查看。 3. 客户端代码应统一接口,无需关心是直接加载图片还是通过代理。 // 1. 抽象接口(Subject) interface Image { void display(); } // 2. 真实对象(RealSubject)

By 李浩