[转]S.O.L.I.D

面向对象设计的原则(OOD&OOP)主要分为两大类,一类是面向类的,另一类是面向包的。设计模式基本都是围绕面向类的几个原则的实践,而面向包的几个原则主要体现在架构模式中。

S.O.L.I.D

Bob大叔(Robert C. Martin)的大名如雷贯耳,相信大部分在进击中的开发者都有阅读过经典著作《敏捷软件开发》的经历,受益匪浅。

在面向对象的程序的设计和开发过程中时,有5个原则非常重要,此外还有一个法则我们应该尽量去遵守它。

1、单一职责原则(SRP,The Single Responsibility Principle)
2、开放封闭原则(OCP,The Open Closed Principle)
3、里氏替换原则(LSP,The Liskov Substitution Principle)
4、依赖倒置原则(DIP,The Dependency Inversion Principle)
5、接口分离原则(ISP,The Interface Segregation Principle)
6、迪米特法则(LoD,The Law of Demeter、LKP)
SRP

A class should have only one reason to change.
一个类应该仅有一个引起它变化的原因。

SRP是所有原则中最简单的一个,概念简洁易懂。但却也是最难正确运用,或者说是最容易过度使用的原则。

一方面,因为SRP把职责定义成了变化的原因,如果我们能够找到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。比如开发者经常会习惯性的把职责归类式的结合在一起,而正确的做法是发现职责并把这些职责相互分离。

另一方面,如果程序的变化方式总是导致N个职责(N>1)同时变化,那么就没必要分离它们了。在这里有一个推论:仅当变化发生时,变化的轴线才具有实际的意义。在实际的设计和开发过程中,一定要把握好分离“单个”职责的度,所谓过犹不及,过度的分离只能适得其反,违背了面向对象的封装思想。

OCP

Software entities(classes,modules,functions,etc.) should be open for extension, but closed for modification.
软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。

OCP是整个面向对象设计的核心。它代表了灵活性、可重用性和可维护性。

乍一看,两个特征似乎有所矛盾,扩展模块的功能通常是以修改模块的源代码作为手段。但是,我们有“抽象”!通过创建稳定的但又能描述一组任意个可能行为的抽象基类,并将具体的行为实现为派生类,这种做法能很好的解决开放扩展的问题。主要是针对软件中频繁变化的那部分作出合理的抽象。

当然,创建和使用抽象会增加软件复杂性和团队的精力,所以肆意的进行抽象显然并不是一个好设计,简直是折磨人。除非你有强大的智商优越感,但是面对广大平凡质朴的程序员,还请手下留情。

拒绝不成熟的抽象和抽象本身一样重要。

LSP

Derived types must be completely substitutable for their base types.
子类型必须能够完全的替换掉它们的基类型。

LSP是使OCP成为可能的主要原则之一,也是继承层次特征的主要设计原则。

一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件中,把父类都替换成它的子类,程序行为没有或者不发生变化。也就是说,只有当子类可以替换掉父类,软件的功能不受到影响时,父类才能真正的被复用,而子类也能够真正的在父类的基础上增加新的行为。

子类型的可替换性使得使用基类型表示的模块在无需修改的情况下就可以扩展。可替换性可以通过显示或者隐式的契约来定义。

DIP

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
高层模块不应该依赖于低层模块,两者都应该依赖于抽象
B. Abstractions should not depend on details. Details should depend on abstractions.
抽象不应该依赖于细节,细节应该依赖于抽象

DIP是面向对象设计的标志。

依赖倒置原则是实现许多面向对象技术所宣称的好处的基本低层机制,他的正确应用对于创建可重用的框架来说是必须的。同时它对于构建在变化面前富有弹性的代码也是非常重要的,由于抽象和细节彼此隔离,所以代码也非常容易维护。

针对接口编程,而不要对实现编程。倒置接口的所有权。

LSP和DIP乍一看还有点相似,其实,他们还是有区别的:

两个原则所站的角度不同。LSP是站在模式对象的角度,而DIP则是站在客户端程序的角度;模式对象一方将“相对多变的”子类视同它的接口(或父类),而客户程序依赖的内容是“相对稳定”的接口。

ISP

Clients should not be forced to depend upon interfaces that they don't use.
不应该强迫客户程序依赖并未使用的接口。

ISP有效的降低了程序间的耦合性,提高了程序集的内聚性。避免了接口污染。

客户程序应该仅仅依赖于他们实际调用的方法。分离客户就是分离接口。通常我们可以使用委托或者使用多重继承来分离接口。

接口隔离原则不是单纯的多余或是不多余,从设计的角度来衡量,它要依据业务领域的需要判断倒是是否真的“多余”,确保在每个领域背景下贯彻不去依赖用不到的方法。通过把胖类的接口分解为多个特定于客户程序的接口,可以实现这个目标。有效的解除了客户程序和它们没有调用到的方法间的依赖关系。

客户程序看到的应该是多个具有内聚接口的抽象基类。

LoD(LKP)

A. Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
B. Each unit should only talk to its friends; don't talk to strangers.
C. Only talk to your immediate friends.

迪米特法则又称为最少知识原则。主要有三层意思,就是让调用者对于目标对象的知识最少,而且只和你的直接朋友对话,千万不要和陌生人说话。

该法则因在《程序员的修炼之道》一书中提及而声名鹊起广为人知。其初衷在于降低类之间的耦合,但是由于通过友元类来建立一个类和其他类的联系,或是减少对其他类的依赖,这导致了在一定程度上增加了系统的复杂度。

小结

这些原则是数十年软件工程经验来之不易的结果。是众多开发人员和研究人员思想和著作的结晶。我们应该牢记面向对象设计的原则,理解OO的设计思路。因为它们有助于开发人员消除拙劣的设计和代码臭味,并能有效的帮助开发人员构建出最适合于当前特性集的设计。

Bob大叔建议:在日常工作中,只有当出现“臭味”时我们才会去使用它,如果只是因为它是一个原则就无条件的遵循它那是错误的,过分的遵循这些原则会导致不必要的复杂性和设计臭味。
原文

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 序言 “佛曰:苦海无涯,回头是岸。——佛教用语” 面向对象(Object-Oriented),这是一条令无数开发人...
    叶小健阅读 2,381评论 4 24
  • 推荐深度好文:原文链接,作者:张洋 序言 Perface “佛曰:苦海无涯,回头是岸。——佛教用语” 面向对象(O...
    不知公民阅读 745评论 0 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 面向对象的3个基本要素: 封装、继承、多态 面向对象的5个基本设计原则: 单一职责原则(Single-Respos...
    badcyc阅读 837评论 0 4
  • “生活不能等待别人来安排,要自己去争取和奋斗,而不论其结果是喜是悲,你总不枉在这世界上活了一场。有了这样的认识,你...
    平舆阅读 207评论 0 1