6大设计原则

6大设计原则


1. 单一职责原则

好处:

  • 类的复杂性降低, 实现什么职责都有清晰明确的定义;
  • 可读性提高, 复杂性降低, 那当然可读性提高了;
  • 可维护性提高, 可读性提高, 那当然更容易维护了;
  • 变更引起的风险降低, 变更是必不可少的, 如果接口的单一职责做得好, 一个接口修
    改只对相应的实现类有影响, 对其他的接口无影响, 这对系统的扩展性、 维护性都有非常大
    的帮助

单一职责原则最难划分的就是职责。 一个职责一个接口,但问题是“职责”没有一个量化的标准, 一个类到底要负责那些职责? 这些职责该怎么细化?
细化后是否都要有一个接口或类?这些都需要从实际的项目去考虑

私以为在开发时间有限的情况下,可以从业务的角度,将某一类业务的操作放入同一个接口中,但是这样更不像是单一职责,而是领域设计?

单一职责适用于接口、 类, 同时也适用于方法, 什么意思呢? 一个方法尽可能做一件事
情, 比如一个方法修改用户密码, 不要把这个方法放到“修改用户信息”方法中, 这个方法的
颗粒度很粗

总结: 这个设计思想仅做指导,在实际中实现难度较大,但是尽量做到接口的职责单一,类的设计尽量做到只有一个原因引起变化。


2. 里氏替换

规则:

  • 子类必须完全实现父类的方法

    如果子类不能完整地实现父类的方法, 或者父类的某些方法在子类中已经发
    生“畸变”, 则建议断开父子继承关系, 采用依赖、 聚集、 组合等关系代替继承。

  • 子类可以有额外的方法和参数

  • 覆盖或实现父类的方法时输入参数可以被放大

    • 实际上就是子类的参数,要和父类一致(重写)或者更大(重载),
  • 覆写或实现父类的方法时输出结果可以被缩小

采用里氏替换原则时, 尽量避免子类的“个性”, 一旦子类有“个性”, 这个子类和父类之间的关系就很难调和了, 把子类当做父类使用, 子类的“个性”被抹杀——委屈了点; 把子类单独作为一个业务来使用, 则会让代码间的耦合关系变得扑朔迷离——缺乏类替换的标准


3. 依赖倒置

  • 高层模块不应该依赖低层模块, 两者都应该依赖其抽象;
  • 抽象不应该依赖细节;
  • 细节应该依赖抽象

依赖倒置原则的本质就是通过抽象(接口或抽象类) 使各个类或模块的实现彼此独立,不互相影响, 实现模块间的松耦合

依赖倒置原则是6个设计原则中最难以实现的原则, 它是实现开闭原则的重要途径, 依赖倒置原则没有实现, 就别想实现对扩展开放, 对修改关闭。 在项目中, 大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心

Spring中的依赖注入是依赖倒置的一种体现

对接口实现类的主动获取变成对接口实现类的依赖依靠外部注入,所以有时候可以称依赖注入为“控制反转”


4. 接口隔离

建立单一接口, 不要建立臃肿庞大的接口。 再通俗一点讲: 接口尽量细化, 同时接口中的方法尽量少

Java中的Class,也可以说成是一种接口,它代表了一种对象的抽象

接口隔离原则与单一职责的审视角度是不相同的, 单一职责要求的是类和接口职责单一, 注重的是职责, 这是业务逻辑上的划分, 而接口隔离原则要求接口的方法尽量少

回顾我之前的开发,接口隔离这一个原则基本上都没有遵守,处于便于查找的考虑,一个接口里将所有此业务相关的接口全部暴露出去,也可能是我们的接口类中接口的数量并没有达到两位数的原因。仔细想,如果接口数量大于10个,是确实可以再次细化职责的区别,拆分成过个接口。但是并不赞同按照所谓的权限和模块划分

其实当前的我开发中遵循的REST风格,其实是把接口的返回当成资源,具体是业务逻辑都在当前项目的service层。这个接口与此处的接口略有不同,此处的接口更倾向于系统内部

《设计模式之禅》中的所谓的星探和美女的例子,私以为是为了体现接口隔离故意弄出来的例子,若真正进行处理,应该是将评价标准进行抽象,然后不同年代仅判断不同的标准即可,美女的接口则不需要进行拆分,增加复杂度

另外有几个点需要注意:

  • 根据接口隔离原则拆分接口时, 首先必须满足单一职责原则
  • 高内局,没必要的方法和接口不用设置成public
  • 定制化权限不同的接口(一个内部使用,返回更加详细或者更大操作权限的接口,一个仅供外部查询的接口)
  • 接口设计是有限度的,细粒度化必将导致复杂度上升,带来开发运维难度的增加,因此要把握一个度,这个度只能由经验去把控

5. 迪米特法则(最少知识原则)

一个对象应该对其他对象有最少的了解

通俗地讲, 一个类应该对自己需要耦合或调用的类知道得最少, 你(被耦合或调用的类) 的内部是如何复杂都和我没关系, 那是你的事情, 我就知道你提供的这么多public方法, 我就调用这么多, 其他的我一概不关心

  • 只和朋友交流

类与类之间的关系是建立在类间的, 而不是方法间, 因此一个方法尽量不引入一个类中不存在的对象

  • 尽量不要对外公布太多的public方法和非静态的public变量, 尽量内敛, 多使用private、 package-private、 protected等访问权限
  • 如果一个方法放在本类中, 既不增加类间关系, 也对本类不产生负面影响, 那就放置在本类中

迪米特法则的核心观念就是类间解耦, 弱耦合, 只有弱耦合了以后, 类的复用率才可以提高。 其要求的结果就是产生了大量的中转或跳转类, 导致系统的复杂性提高, 同时也为维护带来了难度


6. 开闭原则

一个软件实体如类、 模块和函数应该对扩展开放, 对修改关闭

实际上开闭原则是一个非常虚的原则,它“虚”得没有边界, 就像“好好学习, 天天向上”的口号一样, 告诉我们要好好学习, 但是学什么, 怎么学并没有告诉我们, 需要去体会和掌握

具体的可以从以下几点考虑:

  • 抽象约束

通过接口或抽象类可以约束一组可能变化的行为, 并且能够实现对扩展开放, 其包含三层含义:

第一, 通过接口或抽象类约束扩展, 对扩展进行边界限定, 不允许出现在接口或抽象类中不存在的public方法;

第二, 参数类型、 引用对象尽量使用接口或者抽象类, 而不是实现类;

第三, 抽象层尽量保持稳定, 一旦确定即不允许修改。

  • 元数据(metadata) 控制模块行为(即使用配置参数)
  • 制定项目章程(虚的口号 实际中除非人员流动性比较小的公司,不然成本太大)
  • 封装变化

第一, 将相同的变化封装到一个接口或抽象类中;

第二,将不同的变化封装到不同的接口或抽象类中, 不应该有两个不同的变化出现在同一个接口或
抽象类中

23个设计模式都是从各个不同的角度对变化进行封装的

你可能感兴趣的:(6大设计原则)