设计六大原则总结

1、单一职责原则(SRP)

定义:就一个类而言,应该仅有一个引起它变化的原因
为什么需要单一职责呢?如果一个类承担的职责过多,就等于把这些职责耦合在一起了,一个职责的变化可能会引起其它职责的变化,当变化发生时,设计会遭到意想不到的变化。
我们看看下面简单的类图,UserDiscount类具有两个方法,一个是获取等级类型,一个是计算折扣价格。

有两个不同的类在使用UserDiscount,Order需要获取用户等级和计算价格;User只需要获取用户等级,但不需要计算价格,这个设计违反类SRP,如果其中一个使用类的改变导致UserDiscount改变,这样会导致其它使用类也需要变更、测试、部署等问题。我们需要拆分两个职责类,如下图:

但是,如果类的变化总是导致这两个职责的同时变化,那么就不必分离它们,实际上,分离它们可能会导致复杂性增加。或者说,变化的轴线仅当变化实际发生时才具有真正意义。如果没有征兆,那么去应用SRP或者其它原则都是不可取的。
结论:SRP是最简单的职责之一,但是也比较难正确运用的职责,在开发中,会自然地把职责结合在一起,毕竟有些职责需要耦合在一起的,而难以拆分并增加复杂性。

2、开放封闭原则(OCP)

定义:软件实体(类、模块、函数等等)应该是可以扩展的,但是不可以修改的

  • 对于扩展是开放的:模块行为是可以扩展的,当应用需求改变时,我们可以对模块进行扩展,使其满足那些改变的行为。
  • 对于修改是封闭的:对模块扩展时,不必改动模块的源代码

下面来看个播放MP3的例子,MP3和Player都是具体类,MP3直接使用Player播放音乐,但是如果需要播放音频,那么就需要重新修改Player而导致MP3也需要修改。

下面我们修改下例子而遵循OCP原则

这个设计中,IPlayer是一个接口,MP3和Video继承该接口,今后想增加其它类型的播放只需要继承IPlayer就行,无需修改MP3或Video类。
但实际开放中,无论模块多么封闭,都会存在一些无法对之封闭的现象,那就需要有策略的去对待这个问题,模块应该对哪种变化封闭而做出选型,必须先猜测最有可能发生变化的情况,然后构造出抽象来隔离。
结论:遵循OOP可以带来灵活性、可重用性、以及可维护性。然而,对于应用程序中每个部分都肆意的进行抽象同样是不行的,这样属于不成熟抽象,我们只需要把频繁变化的部分进行抽象就行。

3、Liskov替换原则(LSP)

定义:子类型必须能够替换掉它们的基类型
举个例子,函数a使用的参数是基类B,但是C类继承基类B,但把C做为参数传给了函数a而导致其发生错误,这样就是违反了LSP原则。主要体现在下面四个方面:

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

下面来看下简单类图,违反来SRP原则,定义了一个Rectangle和一个继承自Rectangle的Square,看着是非常符合逻辑的,但是我们重新设置Rectangle的宽度,会导致Square的宽度也会变动,导致Square出错。

改变一下不符合SRP,我们再定义一个他们共同的父类Graphics,然后让Rectangle和Square都继承自这个父类。在基类Graphics类中没有赋值方法,因此重设宽高不可能适用于Graphics类型,而只能适用于不同的具体子类Rectangle和Aquare,因此里氏替换原则不可能被破坏。并且下面的设计也符合OCP原则。

结论:使用LSP,使得程序具有更多的可维护性、可重用性以及健壮性。而LSP是使OCP成为可能的主要原则之一,子类型的可替换性才使得基类类型的模块在无需修改的情况下可以扩展。

4、依赖倒置原则(DIP)

定义:高层模块不应该依赖于低层模块,二者应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
下面来看下简单例子,用户有多个用户等级类UseOrdinary和UserDiamond,而UserTypeService使用等级类进行相关的逻辑处理,今后如果增强其它用户等级,就需要修改UserTypeService,这样违反类DIP,高层策略没有和低层实现分离,抽象没有和具体细节分离,没有这种分离,高层策略就自动地依赖于低层策略,抽象就自动地依赖于具体细节。

我们变更下具体的实现方式,抽象出UseType接口,UseOrdinary和UserDiamond继承该接口,而UserTypeService使用了UseType,不管今后增加什么用户等级都无需修改UserTypeService,并对于具体的实现类我们是不管的,只要接口的行为不发生变化,增加新的用户等级后,上层服务不用做任何的修改。这样设计降低了层与层之间的耦合,能很好地适应需求的变化,大大提高了代码的可维护性。

结论:设置倒置的依赖关系结构,使得细节和策略都依赖于抽象,属于面向对象设计;如果依赖关系不倒置,属于过程化设计。

5、接口隔离原则(ISP)

定义:不应该强迫继承类依赖于它们不使用的接口方法,类间的依赖关系应该建立在最小的接口上
使用者依赖了那些它们不使用的方法,就面临着这些未使用的方法改变而带来的变更,无意中导致了它们之间的耦合,下面来看下简单示例,MatchingHandler是一个匹配接口,包含匹配系统ID(handleSystemId)和处理联赛ID(detectLeagueId),MatchMatching和LeagueMatching继承了该接口,但MatchMatching不需要处理处理联赛ID,也继承了该方法,这样方法改变而带来的变更。

我们在来看下变更后的简单类图,新增了LeagueMatchingHandler(detectLeagueId),LeagueMatching继承了该接口,detectLeagueId方法的变更不会导致MatchMatching也需要变更,只会影响到LeagueMatching。

结论:胖类是这个类过于臃肿,可能会导致使用者产生不正常的耦合关系,该类的修改也会导致使用者的修改。使用接口分解,使用者只需要使用特定的接口,并解除了和胖类的耦合关系。

6、迪米特原则(LOD)

定义:类之间尽量与其他实体发生相互作用
在开发中,我们经常提到高内聚低耦合,使各个模块之间的耦合尽量的低,才能提高代码的复用率,耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为低耦合,而出现在局部变量中的类则高耦合。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。下面我们来看下例子,定义了Match,Team和Player,Match都引用了Team和Player,Team又引用了Player,这样违反了LOD,导致了Match跟Player耦合增加。

下面我们来变更下引用,Match只需要引用了Team就行,无需在引用Palyer,因为Team已经引用了Player。这样Match可以打印出相关选手了。

结论:LOD的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系,但这样必须会产生一个中介类,由这个中介类来处理类之间的通信,过多的中介类会导致系统复杂度增大而难以维护。设计的时候需要权衡,保持结构清晰和高内聚低耦合

原文地址:https://www.cnblogs.com/fomin/p/11434300.html

时间: 2024-11-06 09:44:35

设计六大原则总结的相关文章

《设计模式之禅》笔记整理--面对对象设计六大原则

第一章.面对对象设计六大原则: (1).单一职责原则:应该有且只有一个原因引起类的变更. 为什么要用单一职责原则:(1).类的复杂性降低,实现什么职责都有清晰明确的定义. (2).可读性提高,复杂性降低,当然可读性提高了. (3).可维护性提高,可读性提高,当然更容易维护了. (4).变更引起的风险降低,一个接口修改,只对相应的实现类有影响. 职责划分的例子:电话过程可以划分为两个职责:(1).协议管理(2).数据传送 :RBAC模型,基于角色的访问控制 (2).里氏替换原则:目的:增强程序的健

php设计六大原则

1.单一职责 定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 优点: 1).可以降低类的复杂度,一个类只负责一项职责,逻辑简单: 2).提高类的可读性,提高系统的可维护性: 3).变更引起的风险降低,变更是必然的. 2.里氏代换原则 定义:所有引用基类的地方必须能透明地使用其子类的对象,也就是说子类可以扩展父类的功能,但不能改变父类原有的功能 . 3.依赖倒置原则 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 此处理解

设计模式六大原则/接口设计六大原则 之 迪米特法则(转)

定义:一个对象应该对其他对象保持最少的了解.迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话.英文简写为: LoD. 目的:迪米特法则的初衷在于降低类之间的耦合.由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系. 迪米特法则不希望类之间建立直接的联系.如果真的有需要建立联系,也希望能通过它的友元类来

接口设计六大原则

一.单一职责原则 Single Responsibility Principle, 简称SRP. 定义:There should never be more than one reason for a class to change. 应该有且仅有一个原因引起类的变更. 职责的划分?单一的定义和级别? 应该根据实际业务情况而定.关注变化点. 实际使用时,类很难做到职责单一,但是接口的职责应该尽量单一. 二.里氏替换原则 Liskov Substitution Principle, 简称LSP.

设计模式六大原则/接口设计六大原则 之 单一职责原则(1)

Single Responsibility Principle, 简称SRP. 定义:There should never be more than one reason for a class to change. 应该有且仅有一个原因引起类的变更. 职责的划分?单一的定义和级别? 应该根据实际业务情况而定.关注变化点. 实际使用时,类很难做到职责单一,但是接口的职责应该尽量单一.

初识设计模式、软件设计的六大原则

总结:本篇文字分为两个部分.第一部分:设计模式基本常识:第二部分:软件设计中的六大原则,并详细分析了单一职责原则.(本篇文章的时间轴参考:为知笔记支撑文件夹\Java设计模式(时间序列图).vsdx) 部分一:初识设计模式 什么是设计模式?James拿到这个论点时,很是迷惑! 模式?是不是一个模子?模式识别--计算机领域的经典问题? 设计模拟?软件的设计模式?不懂!!! 但是在实际编码.调试过程中,James的遇到过很是难解的问题:工程代码中有过多的冗余代码--代码复用性不高:需求一旦改变,需要

设计模式 之 设计的 六大原则(6) 开放封闭原则

  开放封闭原则  定义:一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. 问题由来:在软件的生命周期内,因为变化.升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试. 解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化. 开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统.开闭原则可能是设计模式六项原则中定义最模糊的一个了,

网页设计之六大原则

随着互联网时代的快速发展,设计师不再只是为互联网创造漂亮美观的图片那么简单了,作为一个WEB设计师,除了基本的设计技能之外,还需要考虑一些其他的问题,比如用户体验,算法,代码等等.如今用户体验设计越来越重要,对于WEB表单的设计尤其如此. WEB表单设计的目标是设计出一套让用户能够从填表到点击提交按钮的最简单的流程.从非常简单直接的表单到花哨.多彩和创意的表单,每个网站都会呈现一种表单风格.不论是登录/注册表单,还是联系表单,或者其他类型表单,设计师们需要牢记一点:这些表单的目标是要赢得用户的注

Java面向对象设计的六大原则

这是设计模式系列开篇的第一篇文章.也是我学习设计模式过程中的总结.这篇文章主要讲的是面向对象设计中,我们应该遵循的六大原则.只有掌握了这些原则,我们才能更好的理解设计模式.我们接下来要介绍以下6个内容. 单一职责原则——SRP 开闭原则——OCP 里式替换原则——LSP 依赖倒置原则——DIP 接口隔离原则——ISP 迪米特原则——LOD 单一职责原则 单一职责原则的定义是就一个类而言,应该仅有一个引起他变化的原因.也就是说一个类应该只负责一件事情.如果一个类负责了方法M1,方法M2两个不同的事