设计模式-七大软件设计原则

设计模式

参考资料

图解设计模式

大话设计模式

设计模式之禅

github我见过最好的设计模式

http://c.biancheng.net/view/1326.html

基本原则

开闭原则

在设计的时候尽可能的考虑,需求的变化,新需求来了尽可能少的改动代码,拥抱变化

定义:指的是软件中一个实体,如类、模块和函数应该对。

面向抽象编程

开闭是对扩展和修改的约束

强调:用抽象构建框架,用实现扩展细节。

优点:提高软件系统的可复用性及可维护性

  • 面向对象最基础的设计原则
  • 指导我们构建稳定的系统
    • 代码不是一次性的,更多时间在维护
    • 大多是代码版本的更新迭代
    • 我们最好对已有的源码很少修改
      • 一般都是新增扩展,类来修改
      • 能够降低风险

关于变化

  • 逻辑变化
    • 比如说算法从变化成其实是可以直接修改的,前提是所有依赖或者关联类都按照相同的逻辑来处理
  • 子模块变化
    • 子模块变化可能直接引起整体也就是高层的变化
  • 可见视图变化
    • 如果说需求上多了一些原有逻辑不存在的,可能这种变化是恐怖的,需要我们灵活的设计

例子

  • 弹性工作时间,时间是固定的,上下班是可变的

顶层接口

接口是规范,抽象是实现

重点

  • 先顶层后细节
  • 自顶向下来思考全局不要一开始沉浸于细节
  • 高层不依赖于低层,关系应该用抽象来维护
  • 针对接口编程不要针对实现编程

以抽象为基准比以细节为基准搭建起来的架构要稳定得多,因此大家在拿到需求之后, 要面向接口编程,先顶层再细节来设计代码结构。

问题

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

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

依赖的常见写法

  • 构造传递依赖对象
  • setter方法传递依赖对象
  • 接口声明传递对象

最佳实践

  • 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽 象才可能依赖倒置。
  • 变量的表面类型尽量是接口或者是抽象类
    • 很多书上说变量的类型一定要是接口或者是抽象类,这个有点绝对 化了,比如一个工具类,xxxUtils一般是不需要接口或是抽象类的。还 有,如果你要使用类的clone方法,就必须使用实现类,这个是JDK提供 的一个规范。
  • 任何类都不应该从具体类派生
    • 如果一个项目处于开发状态,确实不应该有从具体类派生出子类的 情况,但这也不是绝对的,因为人都是会犯错误的,有时设计缺陷是在 所难免的,因此只要不超过两层的继承都是可以忍受的。特别是负责项 目维护的同志,基本上可以不考虑这个规则,为什么工作基本上 都是进行扩展开发,修复行为,通过一个继承关系,覆写一个方法就可 以修正一个很大的Bug,何必去继承最高的基类呢然这种情况尽 量发生在不甚了解父类或者无法获得父类代码的情况下。)
  • 尽量不要覆写基类的方法
    • 如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要 覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会产生一 定的影响。

单一职责原则

  • 接口
  • 方法

只负责一项职责

如果不是这样设计,一个接口负责两个职责,一旦需求变更,修改其中一个职责的逻辑代码会导致另外一个职责的功能发生故障。

案例

上述图片用户的属性和用户的行为并没有分开

  • 下图把

    • 用户信息抽成BO(Business Object,业务对象)
    • 用户行为抽成Biz(Business Logic 业务逻辑对象)

    电话通话会发生下面四个过程

    • 通话
    • 回应
    • 挂机

    上图的接口做了两个事情

    • 协议管理
      • dial 拨 接通
      • hangup 挂机
    • 数据传送
      • chat

    引起变化的点

    1. 协议接通会引起会引起变化(连接导致不传输数据)
    2. 可以有不同的通话方式,

    从上面可以看到包含了两个职责,应该考虑拆分成两个接口

    问题

    为什么要把IAnimal拆分成IFlyAnimal,ISwimAnimal,不拆分会有什么样的问题

    • 一个类所提供的功能应该是他所真正具有的,不拆分会导致他不提供的功能但是强行需要实现,而且会有臃肿的类出现
    • 可能适配器模式也是为了解决这个问题吧

    最佳实践

    • 一个接口只服务于一个子模块或者业务逻辑
    • 通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量 让接口达到“满身筋骨肉”,而不是“肥嘟嘟”的一大堆方法;
    • 已经被污染了的接口,尽量去修改,若变更的风险较大,则采用进行转化处理;
    • 了解环境,拒绝盲从。每个项目或产品都有特定的环境因素,别看到大师是这样做的你就照抄。千万别,环境不同,接口拆分的标准就不同。深入了解业务逻辑,最好的接口设计就出自你的手中!

    迪米特法则

    一个对象应该对其他对象保证最少的了解,也称,如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用,如果其中一个类需要调用另外一个类的某个方法的话,可以

    能够降低类与类之间的耦合

    • 强调只和朋友交流

    • 出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类, 而出现在方法体内部的类不属于朋友类。

    这里面感觉有点职责分开的感觉,不同的对象应该关注不同的内容,所做的事情也应该是自己所关心的

    例子

    teamLeader只关心结果,不关心Course

    问题

    如果以后你要写代码和重构代码你怎么分析怎么重构p>

    1. 先分析相应代码的职责
    2. 把不同的对象需要关心的内容抽离出来
    3. 每个对象应该只创建和关心自己所关心的部分
    4. 一定要使用的话可以通过三方来使用
    5. 合适的使用作用域,不要暴露过多的公共方法和非静态的公共方法

    注意

    迪米特法则要求类“羞涩”一点,尽量不要对外公布太多的 public方法和非静态的public变量,尽量内敛,多使用private、packageprivate、protected等访问权限。

    在实际的项目中,需要适度地考虑这个原则,别为了套用原则而做项目。原则只是供参考,如果 违背了这个原则,项目也未必会失败,这就需要大家在采用原则时反复 度量,不遵循是不对的,严格执行就是“过犹不及”。

    序列化引起的坑

    • 谨慎使用Serializable
      • 在一个项目中使用 RMI(Remote Method Invocation,远程方法调用)方式传递一个 VO(Value Object,值对象),这个对象就必须实现Serializable接口 (仅仅是一个标志性接口,不需要实现具体的方法),也就是把需要 络传输的对象进行序列化,否则就会出现NotSerializableException异 常。突然有一天,客户端的VO修改了一个属性的访问权限,从private 变更为public,访问权限扩大了,如果服务器上没有做出相应的变更, 就会 序列化失败,就这么简单。但是这个问题的产生应该属于项目管 理范畴,一个类或接口在客户端已经变更了,而服务器端却没有同步更 新,难道不是项目管理的失职吗li>

    遵循的原则

    ? 如果 一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响, 那就放置在本类中。

    里氏替换原则

    一个软件实体如果能够适用一个父亲的话,那么一定适用其子类,所有引用父亲的地方必须能透明的使用其子类的对象,子类能够替换父类对象

    • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法
    • 子类中可以增加自己特有的方法
    • 子类的方法重载父类的方法时,入参要比父类的方法输入参数更
    • 子类实现父类方法的时候(重写/重载或实现抽象方法),方法的后置条件(方法的输出,返回)要比父类更加

    例子

    价格重写问题

    价格不是直接重写,而是新写一个方法

    长方形和正方形问题

    问题

    为什么要多用组合和聚合少用继承

    • 继承是侵入性的
    • Java只支持单继承
    • 降低了代码的灵活性,子类多了很多约束
    • 增强了耦合性,父类修改的时候需要考虑子类的修改
      • 会导致关键代码被修改

    总结

    如果你只有一把铁锤, 那么任何东西看上去都像是钉子。

    • 适当的场景使用适当的设计原则
    • 需要考虑,人力,成本,时间,质量,不要刻意追求完美
    • 需要多思考才能用好工具

      我的笔记仓库地址gitee 快来给我点个Star吧

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年11月27日
下一篇 2020年11月27日

相关推荐