设计六大原则总结

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

(0)

相关推荐

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

    设计模式 参考资料 图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 http://c.biancheng.net/view/1326.html 基本原则 开闭原则 在设计的 ...

  • 封装+继承+多态

    面向对象三大特性 封装: Encapsulation是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随意访问.要访问该类 ...

  • 二十三种设计模式修炼手册

    不知不觉,在开发这条道路上摸爬打滚也有些年头了,偶尔回头看看以前写的代码,真可谓粗糙至极.当然了,那时候还是小白,代码写得难看些情有可原,不过现在可不能再用以前的标准去衡量自己了,因此掌握一些高级架构 ...

  • 掌握设计原则,你就是光(25个问题,你会几个)

    25个问题,你会几个 如何理解单一职责原则? 如何判断职责是否足够单一? 职责是否设计得越单一越好? 什么是开闭原则? 修改代码就一定意味着违反开闭原则吗? 怎样的代码改动才被定义为扩展或者说是修改? ...

  • 面向对象六大原则

    这篇文章主要讲的是面向对象设计中,应该遵循的六大原则.只有掌握了这些原则,才能更好的理解设计模式. 我们接下来要介绍以下6个内容. 单一职责原则--SRP 开闭原则--OCP 里氏替换原则--LSP ...

  • 重温设计模式系列(三)面向对象设计原则

    背景 面向对象基础知识,只是给了我们一个概念,如何更好的设计出良好的面向对象代码,需要有设计原则作为支持.设计原则是核心指导思想,在这些原则的基础上,经过不断的实践,抽象,提炼逐步产生了针对特定问题的 ...

  • 设计模式——六大设计原则

    文章目录 一.单一职责原则 二.里式替换原则 三.依赖倒置原则 四.接口隔离原则 五.迪米特法则 六.开闭原则 一.单一职责原则 单一职责原则简称 SRP,他想表达的就是字面意思,一个类只承担一个职责 ...

  • 软件设计的六大原则剖析

    我们平时编写代码时,很少有人为了刻意迎合软件设计原则而编写.其实,有时候是你用到了其中的某个或多个设计原则,而不自知而已.也有可能是有的人压根就不知道设计原则是什么. 不过,没关系,为了搞明白既抽象又 ...

  • 设计研学方案的六大原则

    来源 | <基础教育参考>  整理 | 未名研学导语 研学方案的设计应侧重于培养学生的实践能力和创新思维,让学生在实践中探索,在探究中发现,从而提高学生自主.合作.探究的能力.同时,必须注 ...

  • 科三考试六大原则,学员提前收藏

    科三,是公认的驾考难点,不少学员在此项目上接二连三失利.但也有学员一次性通过,只是这样的成功太难复制.有着丰富教学经验的教练给出了科三考试六大原则,只要全部做到,就能大概率一次性通过科三,各位学员还不 ...

  • 飞机设计六大缺憾

    8月20日凌晨,美国联邦快递一架波音767货机在洛杉矶机场降落时发生险情.因为左主起架无法放下,被迫冒险着地.从视频中可以看到,左发动机擦地冒出大量火花.幸亏飞机姿态掌控的非常好,未偏出跑道,也没有着 ...

  • 详细讲解:森林旅游产品设计六大要点【智美旅游策划 第1115期】

    森林旅游是在特定的森林地域为旅游者提供游览观光.度假休闲.狩猎探险.健身疗养.科普教育等多种旅游产品和服务的一种特色旅游.下面为大家介绍森林公园旅游产品设计六大要点! 一.开发以保护为前提 森林公园的 ...

  • 管理者核心能力提升74:优秀管理者必须坚持管人六大原则

    作者:嵇国光管理视界 摘要:我是管理者,更是领导者.管理循环和领导循环两者啮合着.推动着团队前行.对人讲灰度,对事讲流程!领导管人,流程管事.前者是领导,后者是管理. 领导管人,流程管事.管理者在管人 ...

  • 管理者核心能力提升75:优秀管理者必须坚持横向管理六大原则

    作者:嵇国光管理视界 摘要:我是管理者,更是领导者.管理循环和领导循环两者啮合着.推动着团队前行.对人讲灰度,对事讲流程!领导管人,流程管事.前者是领导,后者是管理. 作为一名管理者,不仅要管好人,管 ...

  • 冠心病患者出游的六大原则,出门前先看一看!

    哈特瑞姆心脏科普推荐搜索 冠心病 预防 猝死 马上就是五一了,小哈提醒您出门在外一定注意安全第一,因突发心脏病火车上紧急救援.飞机迫降的新闻报道时有发生,而心脏性猝死的病因中冠心病占有三分之二! 冠心 ...

  • 股权合伙激励六大原则解读

    直入主题,做股权合伙激励实际操作要考虑六大原则: 一是进入机制.你是在总公司做股权激励?还是在子公司.事业部做股权激励?如果是开分店(分校),是让店长投入,还是让店员或是导购员投入?这必须要有一个标准 ...