设计模式学习
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
设计模式的分类三个类别。共有23种模式
- 构建型(创建型)
- 结构型
- 行为型
数了数图有25种不对劲带ok的那两个模式可以去掉。
五或六或七大原则
SOLID
- 开闭原则(Open Closed Principle, OCP)
- 单一职责原则(Single Responsibility Principle, SRP)
- 里氏替换原则(Liskov Substitution Principle, LSP)
- 依赖倒置原则(Dependency Inversion Principle, DIP)
- 接口隔离原则(Interface Segregation Principle, ISP)
- 合成/聚合复用原则(Composite/Aggregatte Reuse Principle, CARP)
- 最少了解原则(Least Knowledge Principle, LKP)或迪米特法则(Law Of Demeter, LOD)
开闭原则OCP
简而言之就是对扩展开放对修改关闭。比如要增加新的功能通过增加一个实现类来实现而不是修改原有的代码来实现。比如Android app中将图片获取功能抽象出一个接口接口中实现一个获取图片方法增加一个类实现接口内部使用Universal Image Loader库进行图片获取后续比如Glide库更好这时候增加一个新的类实现这个接口内部图片获取方式改为Glide即可完成图片获取方式 的替换而避免了原有代码大量的修改。会更加的灵活。
定义一个软件实体如类、模块和函数应该对扩展开放对修改关闭。模块应尽量在不修改原是"原"指原来的代码代码的情况下进行扩展。
单一职责原则SRP
比如Activity或Fragment中一般用来显示和交互如果里面有网络请求的逻辑文件读写的逻辑就违反了SRP引起Activity变化的原因就会增加从而造成Acttivity代码臃肿难以维护混乱和复杂。
定义指一个类或者模块应该有且只有一个改变的原因。如果一个类承担的职责过多就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计当发生变化时设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性。
里氏替换原则LSP
定义所有引用基类的地方必须能透明地使用其子类的对象也可以简单理解为任何基类可以出现的地方子类一定可以出现。
只有当衍生类可以替换掉基类软件单位的功能不受到影响时基类才能真正被复用而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对"开-闭"原则的补充。实现"开-闭"原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现所以里氏代换原则是对实现抽象化的具体步骤的规范。当然如果反过来软件单位使用的是一个子类对象的话那么它不一定能够使用基类对象。举个很简单的例子说明这个问题如果一个方法接收Map类型参数那么它一定可以接收Map
的子类参数例如HashMap
、LinkedHashMap
、ConcurrentHashMap
类型的参数但是反过来如果另一个方法只接收HashMap
类型的参数那么它一定不能接收所有Map
类型的参数否则它可以接收LinkedHashMap
、ConcurrentHashMap
类型的参数。
依赖倒置原则DIP
定义程序要依赖于抽象接口不要依赖于具体实现。简单的说就是要求对抽象进行编程不要对实现进行编程这样就降低了客户与实现模块间的耦合。
意义依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中尽量引用层次高的抽象层类即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明以及数据类型的转换等而不要用具体类来做这些事情。为了确保该原则的应用一个具体类应当只实现接口或抽象类中声明过的方法而不要给出多余的方法否则将无法调用到在子类中增加的新方法。在引入抽象层后系统将具有很好的灵活性在程序中尽量使用抽象层进行编程而将具体类写在配置文件中这样一来如果系统行为发生变化只需要对抽象层进行扩展并修改配置文件而无须修改原有系统的源代码在不修改的情况下来扩展系统的功能满足开闭原则的要求。
接口隔离原则ISP
定义客户端不应该依赖它不需要的接口类间的依赖关系应该建立在最小的接口上。简单来说就是建立单一的接口不要建立臃肿庞大的接口。也就是接口尽量细化同时接口中的方法尽量少。
如何看待接口隔离原则和单一职责原则
单一职责原则注重的是类和接口的职责单一这里职责是从业务逻辑上划分的但是在接口隔离原则要求当一个接口太大时我们需要将它分割成一些更细小的接口使用该接口的客户端仅需知道与之相关的方法即可。也就是说我们在设计接口的时候有可能满足单一职责原则但是不满足接口隔离原则。
接口隔离原则的规范
- 使用接口隔离原则前首先需要满足单一职责原则。
- 接口需要高内聚也就是提高接口、类、模块的处理能力少对外发布public的方法
- 定制服务只提供访问者需要的方法。
- 接口设计是有限度的接口的设计粒度越小系统越灵活但是值得注意不能过小否则变成"字节码编程"。
合成/聚合复用原则CARP
定义尽量使用合成/聚合而不是通过继承达到复用的目的。
合成/聚合复用原则就是在一个新的对象里面使用一些已有的对象使之成为新对象的一部分新的对象通过向内部持有的这些对象的委派达到复用已有功能的目的而不是通过继承来获得已有的功能。
聚合(Aggregate)
聚合表示一种弱的"拥有"关系一般表现为松散的整体和部分的关系其实所谓整体和部分也可以是完全不相关的。例如A对象持有B对象B对象并不是A对象的一部分也就是B对象的生命周期是B对象自身管理和A对象不相关。比如一群大雁和一只大雁群体和个体的弱拥有关系。
合成/组合(Composite)
合成表示一种强的"拥有"关系一般表现为严格的整体和部分的关系部分和整体的生命周期是一样的。比如一头牛和牛头则是一种整体和部分的强拥有关系。
为什么要用合成/聚合来替代继承达到复用的目的
继承复用破坏封装特性因为继承将基类的实现细节暴露给派生类基类的内部细节通常对子类来说是可见的这种复用也称为"白箱复用"。这里有一个明显的问题是派生类继承自基类如果基类的实现发生改变将会影响到所有派生类的实现如果从基类继承而来的实现是静态的不可能在运行时发生改变不够灵活。
由于合成或聚合关系可以将已有的对象一般叫成员对象纳入到新对象中使之成为新对象的一部分因此新对象可以调用已有对象的功能这样做可以使得成员对象的内部实现细节对于新对象不可见所以这种复用又称为"黑箱"复用相对继承关系而言其耦合度相对较低成员对象的变化对新对象的影响不大可以在新对象中根据实际需要有选择性地调用成员对象的操作合成/聚合复用可以在运行时动态进行新对象可以动态地引用与成员对象类型相同的其他对象。
迪米特法则LOD
定义一个软件实体应当尽可能少地与其他实体发生相互作用。每一个软件单位对其他的单位都只有最少的了解而且局限于那些与本单位密切相关的软件单位。迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖因此很容易使得系统的功能模块功能独立相互之间不存在或很少有依赖关系。迪米特法则不希望类之间建立直接的联系。如果真的有需要建立联系也希望能通过它的友元类中间类或者跳转类来转达。
规则
- Only talk to your immediate friends(只与直接的朋友通讯)一个对象的"朋友"包括他本身(this)、它持有的成员对象、入参对象、它所创建的对象。
- 尽量少发布public的变量和方法一旦公开的属性和方法越多修改的时候影响的范围越大。
- “是自己的就是自己的”如果一个方法放在本类中既不产生新的类间依赖也不造成负面的影响那么次方法就应该放在本类中。
意义
迪米特法则的核心观念就是类间解耦也就降低类之间的耦合只有类处于弱耦合状态类的复用率才会提高。所谓降低类间耦合实际上就是尽量减少对象之间的交互如果两个对象之间不必彼此直接通信那么这两个对象就不应当发生任何直接的相互作用如果其中的一个对象需要调用另一个对象的某一个方法的话可以通过第三者转发这个调用。简言之就是通过引入一个合理的第三者来降低现有对象之间的耦合度。但是这样会引发一个问题有可能产生大量的中间类或者跳转类导致系统的复杂性提高可维护性降低。如果一味追求极度解耦那么最终有可能变成面向字节码编程甚至是面向二进制的0和1编程。
小结
说实话设计模式的七大原则理解是比较困难的我们在设计模式的学习和应用中经常会听到或者看到"XXX模式符合XXX原则"、"YYY模式不符合YYY原则"这样的语句。因此为了分析设计模式的合理性和完善我们日常的编码掌握和理解这七大原则是十分必要的。
本文对其他博客内容复制粘贴严重感谢大佬向原作者致敬引用链接记在下面。在开发中设计模式原则方面目前也太偏重于理论在实践中有些原则的体会是没有的或是非常浅显的。
参考
https://cloud.tencent.com/developer/article/1665573
https://blog.csdn.net/SEU_Calvin/article/details/66994321
xmind画图
https://blog.csdn.net/skytruine/article/details/105828748
类图
https://blog.csdn.net/horsee/article/details/113883818
设计模式的原则
https://cloud.tencent.com/developer/article/1650116