用代码来说29种业务场景下的29种设计模式

借鉴博文与书籍

借鉴博文:https://blog.csdn.net/u011642663/article/details/90597317
书籍:《设计模式之禅》

六大原则

单一职责原则

概念:一个接口只做一件事

优点

  1. 代码可读性提高,可维护性提高,复杂性降低。

  2. 变更引起的风险降低。变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。(来自《设计模式之禅》)

业务场景

修改用户名、修改密码

错误代码示范 - 原因:不能把修改用户名和修改密码两个操作放在一个接口中
在这里插入图片描述

参考代码
在这里插入图片描述

总结
凡事都有两面性,过细的划分接口也会有不好的影响。推开业务需求来讲设计模式就是耍流氓。

依赖倒置原则

概念:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的,接口或抽象类不依赖于实现类,实现类依赖接口或抽象类 ——《设计模式之禅》

业务场景
老板下有员工

错误代码示范 - 原因:老板的实现类和员工的实现类发生了依赖关系
在这里插入图片描述

参考代码 - 老板只与员工的抽象类产生依赖
在这里插入图片描述
总结
高质量代码的优点无非就是简洁、易懂、低耦合。而依赖关系建立在接口或者抽象类上,就达到了解耦的目的。

里氏替换原则

概念:父类能做的事,子类一定能做,并且子类不能去改造父类的方法。

优点

  1. 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性。
  2. 提高代码的重用性。
  3. 子类可以形似父类,但又异于父类,可以新增方法、属性,但不能去重写父类的方法。

缺点

  1. 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法。
  2. 降低代码的灵活性。子类必须拥有父类的属性和方法,具有局限性。
  3. 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果————大段的代码需要重构。(来自《设计模式之禅》)

错误代码示范 - 原因:子类不能去改写父类的方法
在这里插入图片描述

参考代码 - 子类新增自己的方法
在这里插入图片描述

接口隔离原则

概念:实现类不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上

优点

1.接口功能最小化

缺点
1.增加代码量

业务场景
猫会吃鱼,人会吃肉和看书

错误代码示范 - 原因:动物接口中的看书行为,猫不需要
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916133420408.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
参考代码 - 各取所需
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916133424605.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
总结
接口隔离原则最最最重要一点就是要根据实际情况,具体业务具体分析。

迪米特原则

概念:每个单元相对于其他的单元只能拥有有限的知识,每个单元只能和它直接关联的单元联系 ——《设计模式之禅》

业务场景
用手机打开APP聊天

错误代码示范 - 原因:Phone应该只和App有关,不应该和具体的App微信有关系
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916165113438.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70

参考代码 - Phone只与App有关,App与Wechat有关
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916165117279.png

总结
迪米特法则主要讲述的观点是高内聚、低耦合。我理解为:触手可及的东西我要,超出伸手范围的与我无关。

开闭原则

概念:程序中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的

优点
1.代码的可维护性高

业务场景
根据不同的客户等级,对商品进行打折

错误代码示范 - 原因:如果之后新增了客户等级,则需要在源代码中新增if条件,不满足开闭原则
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916165254984.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
参考代码 - 新增等级只需要维护map里的数据,甚至可以写在配置文件里进行读取
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916165307156.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
总结
工作中,改BUG的时候最怕去修改别人的代码了。如果该方法被多个地方调用,很可能改好了一个BUG又制造出了新的BUG,所以说代码扩展是开放的,对于修改是封闭的是很重要的。

五大创建型模式

单例模式

概念:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例

业务场景
开车去做不同的事

错误代码示范 - 原因:从输出的结果可以看出,两次用的不是一辆车
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916170215792.png
参考代码 - 在类加载的时候就完成实例化
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916170220573.png
总结
单例模式在项目中的运用如项目的配置文件加载、各种工具类等等。我们对于单例模式最重要的一点就是要考虑多线程并发,没有考虑这点就容易引发单例对象不单例的情况。而单例给我们带来最大的好处就是节约内存。

原型模式

概念:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

业务场景
复印机复印文件

错误代码示范 - 原因:同样的一份文件,不需要进行5次实例化
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916171715517.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
在这里插入图片描述
参考代码
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019091617172344.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
在这里插入图片描述
总结
通过原型模式,绕过构造方法创建对象,利用内存直接拷贝对象,提高对象的创建性效率。在有大量的对象创建或者类初始化消耗多资源的场景下可以利用原型模式来优化。

工厂方法

概念:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类(来自《设计模式之禅》)

业务场景
开小汽车去上学,开摩托车去参加派对

简单工厂代码参考
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916171905830.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916171910523.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
工厂方法代码参考
在这里插入图片描述
在这里插入图片描述
总结
工厂方法模式具有可扩展性。工厂方法是在解决一个产品多个层级方面的事情(不同车库里不同的车)

建造者模式

概念:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示(来自《设计模式之禅》)

业务场景
在烤鸡翅和烤茄子的制作流程中,加的调料和烧烤时间是不同的

错误代码示范 - 原因:各操作的顺序是由烧烤人去决定的,甚至有可能忘记放配料
在这里插入图片描述
在这里插入图片描述
参考代码
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916172036826.png
由建造者来决定制作流程
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916172041174.png
向外提供的只有菜单,通过点菜来决定吃什么
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190916172045174.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
在这里插入图片描述
总结
通过建造者模式,可以把本来强依赖的东西解绑,不仅仅解决依赖问题,还提高了封装性,让使用者不用明白内部的细节。

抽象工厂

概念:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类(来自《设计模式之禅》)

业务场景
宝马和特斯拉两个汽车工厂分别造自己品牌的轮胎和方向盘

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结
在单产品多层级,层级数量不多的情况下,可以使用简单工厂,层级多且需要支持扩展,可以使用工厂方法;在多产品多层级,可以使用抽象工厂。

十一大行为模式

中介者模式

概念:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。(来自《设计模式之禅》)

业务场景
租房子

错误代码示范 - 原因:顾客和房东产生了强耦合,顾客在看房的时候不需要和房东联系
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190917094538637.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70

参考代码 - 引入房地产中介,进行解耦
在这里插入图片描述
在这里插入图片描述
总结
中介者模式通过在互相依赖的对象中间加了一层,让原本强依赖的对象变成弱依赖。常用的就是 MVC 框架,就是典型的中介者模式。通过 Controller (控制层) 将 Model (业务逻辑层) 和 View (视图层) 的依赖给分离开,协调 Model 和 View 中的数据和界面交互工作。

命令模式

概念:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。(来自《设计模式之禅》)

业务场景
开发经理下达命令给开发人员

错误代码示范 - 原因:开发经理和开发人员产生了强依赖,当开发人员新增功能时,开发经理的action方法也需要新增判断
在这里插入图片描述
参考代码
在这里插入图片描述
在这里插入图片描述
总结
利用命令模式能够进行类的解耦,让调用者和接受者没有任何关系,也通过对行为的抽象,让新增其他行为变得清晰容易,也就是可扩展性大大增加。

模板方法

概念:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 ——《设计模式之禅》

业务场景
宝马和特斯拉的组装流程

参考代码
在这里插入图片描述
总结
框架的源码中经常会用到模板方法。比如Dubbo,Dubbo可以支持多种注册中心,就是使用了模板方法设计模式,保证了可扩展性,也统一了代码的规范。

策略模式

概念:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。(来自《设计模式之禅》)

业务场景
上车刷卡

参考代码
在这里插入图片描述

总结
常见的if判断,加上封装就是策略模式了,为了不把策略对外暴露,会结合工厂模式一起使用。

责任链模式

概念:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。(来自《设计模式之禅》)

业务场景
HR一面,技术组长二面

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结
责任链模式很好的把处理的逻辑封装起来,在代码中,只看到了HR面试,其实还有技术组长的面试。Filter过滤器的链式过滤就是基于责任链的设计模式设计的。

迭代器模式

概念:它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。(来自《设计模式之禅》)

业务场景
列表循环播放音乐

不使用迭代器
在这里插入图片描述

使用迭代器
在这里插入图片描述
总结
迭代器可以让容器有统一的遍历代码风格,不用各自去实现遍历方法,有更好的封装性。Java 中访问 MySQL 获取数据就是用迭代器来遍历数据的。

观察者模式

概念:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。(来自《设计模式之禅》)

业务场景
公众发布文章,关注的人可以收到

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
朋友圈、MQ也都用到了观察者的设计模式,核心在于消息的订阅与通知。

状态模式

概念:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。(来自《设计模式之禅》)

业务场景
不同的用户,权限不同

错误代码示范 - 原因:扩展性不高,假设新增了一个角色,多处需要修改
在这里插入图片描述
参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
状态模式降低了代码的复杂性,提高了可维护性。大多数的业务场景下的if - else都可以用状态模式来进行优化。

备忘录模式

概念:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。(来自《设计模式之禅》)

业务场景
项目的发布

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
数据库的事务回滚也用到了备忘录设计模式的思想。

解释器模式

概念:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。(来自《设计模式之禅》)

业务场景
Java代码中的SQL的解析与拼接

正确代码参考
在这里插入图片描述

总结
解释器模式就像是翻译官,让不同的语言能进行交互。

访问者模式

没弄明白,感觉有些鸡肋。推荐一篇博文。https://mp.weixin.qq.com/s/PA0bdeeFYY3UEwNYfqH6IA

七大结构性模式

适配器模式

概念:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。(来自《设计模式之禅》)

业务场景
在美国使用适配器给中国电器充电

参考代码
在这里插入图片描述

总结
IO流里面的字节流与字符流的转换就用到了适配器设计模式的思想。

桥接模式

概念:将抽象和实现解耦,使得两者可以独立地变化。(来自《设计模式之禅》)

业务场景
Android和IOS手机打开APP

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
桥接模式利用了聚合的优点去解决继承的缺点,使得抽象和实现进行分离解耦。正由于解耦,使得有更好的扩展性,加手机类型或者加软件都非常容易,也不会破坏原有的代码。

组合模式

概念:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。(来自《设计模式之禅》)

业务场景
项目人员结构

错误代码示范 - 原因:三个角色的代码都有共同点,代码冗余了
![![在这里插入图片描述](https://img-blog.csdnimg.cn/20190921165007738.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70](https://img-blog.csdnimg.cn/20190921165053306.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3Njc0MQ==,size_16,color_FFFFFF,t_70
正确代码参考
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结
组合模式的优势在于多变性,可以根据业务场景来进行自由的组合,减少代码的冗余。

装饰模式

概念:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活(来自《设计模式之禅》)

业务场景
制作蜂蜜烧仙草和蜂蜜牛奶烧仙草

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结
装饰模式可以实现多继承的效果,有更好的扩展性,也比较灵活。但似乎违背了里氏替换的原则,子类去重写了父类的方法。在 Java JDK 源码中也大面积用到了装饰模式,比如:java.io.BufferedInputStream(InputStream)。

外观模式

概念:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。(来自《设计模式之禅》)

业务场景
新需求来了,开发人员开始开发,测试人员负责测试

错误代码示范 - 原因:如果开发和测试人数较多,一个需求需要交接好几遍
在这里插入图片描述
在这里插入图片描述

参考代码
在这里插入图片描述
在这里插入图片描述

总结
外观模式统一口径、一致对外,通过一个对外统一的接口,隐藏了内部的具体实现,使得外部系统可以更加简单的访问,也减少了外部系统对内部系统的依赖,从上面的例子讲,如果开发同学开发一半生病短时间无法来上班,交接给其他同学,由组长内部安排解决,需求同学并不需要知道。外观模式在微服务交互之间经常使用。

享元模式

概念:使用共享对象可有效地支持大量的细粒度的对象。(来自《设计模式之禅》)

业务场景
用蜡笔画画

错误代码示范 - 原因:相同颜色的笔,可以共用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
享元模式用到了单例模式的设计思想,合理提高了对象的复用性,减少了程序的内存占用,还有一个提高性能的地方就是减少了对象创建的过程。

代理模式

概念:为其他对象提供一种代理以控制对这个对象的访问。(来自《设计模式之禅》)

业务场景
微服务的网关代理

正确代码参考
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结
代理模式简单说就是在原来对象的功能基础上加上额外的功能。比如Spring的AOP、数据权限的过滤也用到了代理模式的设计思想。

猜你喜欢

转载自blog.csdn.net/weixin_43776741/article/details/100881583
29