软件6大设计原则

一. 单一职责原则(Single Responsiblity Principle,SRP)

定义:应该有且仅有一个原因引起类的变更 。

要求:一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,它就负责一件事情。

好处:

  1. 明确定义类的职责,复杂性降低,
  2. 可读性提高,
  3. 可维护性提高,
  4. 变更引起的风险降低,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

二. 里氏替换原则(Liskov Substitution Principle,LSP)

定义:
第一种定义,如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
第二种定义:所有引用基类的地方必须能透明地使用其子类的对象。

规范(含义):

  1. 子类必须完全实现父类的方法;
    1. 在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则;
    2. 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。
  2. 子类可以有自己的个性;
  3. 覆盖或实现父类的方法时输入参数可以被放大;
    1. 如果父类的输入参数类型大于子类的输入参数类型,会出现父类存在的地方,子类未必会存在,因为一旦把子类作为参数传入,调用者很可能进入子类的方法范畴;
    2. 子类中方法的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松。
  4. 覆写或实现父类的方法时输出结果可以被缩小。
    1. 父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一个类型,要么S是T的子类。
      采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续执行。

三. 依赖倒置原则(Dependence Inversion Principle,DIP)

定义:

  1. 高层模块不应该依赖底层模块,两者都应该依赖抽象;
  2. 抽象不应该依赖细节;
  3. 细节应该依赖抽象。

高层模块/低层模块:每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是底层模块,原子逻辑的再组装就是高层模块。

在Java语言中的表现(面向接口编程):

  1. 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
  2. 接口或抽象类不依赖于实现类;
  3. 实现类依赖接口或抽象类。

对象的依赖关系传递方式:

  1. 构造函数传递依赖对象 — 在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入。
  2. Setter方法传递依赖对象 — 在抽象中设置Setter方法声明依赖关系,依照注入的说法,这是Setter依赖注入。
  3. 在接口的方法中声明依赖对象,这种方式也叫做接口注入。

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

依赖导致规则:

  1. 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备; — 这是依赖倒置的基本要求,接口或抽象类都是属于抽象的,有了抽象才可能依赖倒置。
  2. 变量的表面类型尽量是接口或者是抽象类;
  3. 任何类都不应该从具体类派生;
  4. 尽量不要覆写基类的方法;
    如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会产生一定的影响。
  5. 结合里氏替换原则使用。
    接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。

四. 接口隔离原则(Interface Segregation Principle,ISP)

定义:客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。

接口隔离原则是对接口进行规范约束,其包含以下4层含义:

  1. 接口要尽量小; — 这是接口隔离原则的核心定义,不出现臃肿的接口,但是“小”是有限度的,首先就是不能违反单一职责原则。
  2. 接口要高内聚; — 高内聚就是提高接口、类、模块的处理能力,减少对外的交互。在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也越有利于降低成本。
  3. 定制服务; — 一个系统或系统内的模块之间必然会有耦合,有耦合就要有相互访问的接口(并不一定就是Java中定义的Interface,也可能是一个类或单纯的数据交换),我们设计时就需要为各个访问者(即客户端)定制服务。定制服务就是单独为一个个体提供优良的服务。我们在做系统设计时也需要考虑对系统之间或模块之间的接口采用定制服务。采用定制服务就必然有一个要求:只提供访问者需要的方法。
    接口设计是有限度的。 — 接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂化,开发难度增加,可维护性低,这不是一个项目或产品所期望看到的,所以接口设计一定要注意适度。

接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。但是,这个原子该怎么划分是设计模式中的一大难题,在实践中可以根据以下几个规则来衡量:

  1. 一个接口只服务于一个模块或业务逻辑;
  2. 通过业务逻辑压缩接口中的public方法;
  3. 已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理;
  4. 了解环境,拒绝盲从,每个项目或产品都有特定的环境因素,环境不同,接口拆分的标准就不同。

五. 迪米特法则(Law of Demeter ,LoD)/最少知识原则(Least Knowledge Principle,LKP)

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

迪米特法则对类的低耦合提出了明确的要求,其包含以下4层含义:

  1. 只与直接的朋友通信 — 朋友类的定义:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。注意:一个类只和朋友交流,不与陌生类交流,类与类之间的关系是建立在类间的,而不是方法间,因此一个方法尽量不引入一个类中不存在的对象,当然,JDK API提供的类除外。
  2. 朋友间也是有距离的 — 尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。
  3. 是自己的就是自己的 — 如果一个方法放在本类中,即不增加类间的关系,也对本类不产生负面影响,就放置在本类中。
  4. 谨慎使用Serializable

迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提高,同时也为维护带来了难度。
  
在实际的项目中,需要适度地考虑这个原则,别为了套用原则而做项目。原则只是供参考,如果违背了这个原则,项目也未必会失败,这就需要大家在采用原则时反复度量,不遵循是不对的,严格执行就是“过犹不及”。

六. 开放封闭原则

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值