设计模式-问题-设计原则

开闭原则

为什么要遵循开闭原则,从软件工程角度怎么理解这点。

  • 作为一名软件开发人员如果你去修改别人的代码可能会造成隐患,因为以有的代码是已经上线了且经过测试了的。

  • 关于变化

    • 如果是变量,逻辑变化,直接修改是没有问题的

    • 但是如果是子模块的变化会直接导致所有依赖当前子模块的高层都变化

    • 需求的变更可能导致我们整块代码都不可用

  • 遵循开闭原则能够降低后期维护和修改的风险

  • 常见的开闭原则

    • 抽象约束

    • 配置文件

  • 我们设计软件需要多考虑,以及未来可能产生的变化

依赖倒置原则

为什么要依赖抽象,抽象表示我还可以扩展还没有具体实现,用自己的话来解释一遍

  • 例如说制作一辆车,车可能需要关心的是车的座椅,轮子

    • 如果说我直接说车关心的是车的座椅是真皮的,轮子是特定的品牌的那么之后我们需要扩展,或者说更改座椅的类型,车轮子的品牌都需要从上往下来更改

  • 其实还是为了高内聚和低耦合

  • 一般软件中抽象分成两种,接口和抽象类,接口是规范,抽象是模板,我们通过抽象的方式,也就是使用规范和模板这样我们能够使得上层,也就是调用层能够复用逻辑,而我们底层是能够快速更改实现的,例如Spring的依赖注入,Dubbo的SPI,SpringBoot的SPI都如此

  • 关于使用

    • 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽 象才可能依赖倒置。

    • 变量的表面类型尽量是接口或者是抽象类

      • 很多书上说变量的类型一定要是接口或者是抽象类,这个有点绝对 化了,比如一个工具类,xxxUtils一般是不需要接口或是抽象类的。还 有,如果你要使用类的clone方法,就必须使用实现类,这个是JDK提供 的一个规范。

    • 任何类都不应该从具体类派生

    • 尽量不要覆写基类的方法

      • 也违背了里氏替换原则

    • 如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要 覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会产生一 定的影响。

单一职责原则

举个例子什么场景下需要考虑到单一职责原则为什么要考虑到它,如果没有单一职责给后期维护变更带来什么麻烦

  • 其实单一职责原则真正关心的还是不要存在一个导致类变更的原因

  • 例如说打电话我们分成以下几个步骤

    • 拨号

    • 通话

    • 回应

    • 挂机

  • 拨号和挂机应该放在一起

  • 通话和回应应该放在一个层面

    • 因为挂机和通话会影响通话和回应

    • 通话回应有可能有不同的例如打电话上网

    • 实际上他们是两个层面的东西,所以应该考虑拆成两块,连接管理层和数据传输层

例如说我们的网络七层模型

  • 应用层

  • 表示层

  • 会话层

  • 传输层

  • 网络层

  • 数据链路层

  • 物理层

分层之后,每一层只需要关心自己的职责和功能就行了,底层变化不会导致上层需要修改

有的时候我们具体的单一职责可能要受到多方面因素的影响例如

  • 工期

  • 成本

  • 技术水平

  • 硬件

  • 网络

  • 政策

等但是我们都需要竟可能的做到单一职责,这样才能做到符合开闭原则,以后不会因为一个地方的变更导致各处都需要修改

接口隔离原则

为什么要把IAnimal拆分成IFlyAnimal,ISwimAnimal,不拆分会有什么样的问题这节课怎么讲

  • 因为有的动物并没有这些功能

  • 每个具体的实现都应该值关心自己真正关心的东西

  • 有的时候没有办法,可以采用适配器模式

  • 我们需要尽可能建立单一接口,不要简历庞大臃肿的接口

  • 竟可能的细化接口,接口的方法尽可能的少

  • 一个接口一个方法应该只服务于一个子模块或者业务逻辑

  • 合适的使用作用域

迪米特原则

画出TeamLeader/Employee/Course之间交互关系通体会一下,如果以后你要写代码和重构代码你怎么分析怎么重构?你也可以查看他们类之间的关系来仔细体会。

image-20201229171207046
  1. 先分析相应代码的职责

  2. 把不同的对象需要关心的内容抽离出来

  3. 每个对象应该只创建和关心自己所关心的部分

  4. 一定要使用的话可以通过三方来使用

  5. 合适的使用作用域,不要暴露过多的公共方法和非静态的公共方法

里氏替换原则

你怎么理解里氏替换原则,为什么要保证使用父类的地方可以透明地使用子类。

  • 因为我们可能大多数时候使用依赖导致原则,面向抽象编程,可能大多数情况都是使用的抽象,如果使用父类的地方不能透明的使用子类就会导致我们上层使用的是错误的

要保证可以透明使用子类在哪些具体的场景需要注意。

  • 子类可以实现父类的抽象方法,但是不能重写非抽象方法

  • 子类可以增加自己特有的方法

  • 子类重载父类方法时,入参要比父类的方法入参更加宽松,返回值要比父类的更加严格

  • 子类必须实现父类中没有实现的方法

  • is-a的问题

  • 如果父类的地方替换成子类不行的话程序复杂性增加,继承反而带来了程序的复杂度

  • 子类只能在父类的基础上增加新的方法

合成复用原则

想一想为什么要多用组合少用继承。

  • 继承是侵入性的

  • Java只支持单继承

  • 降低了代码的灵活性,子类多了很多约束

  • 增强了耦合性,父类修改的时候需要考虑子类的修改

    • 会导致关键代码被修改

Last updated