世纪的前几年里,“ Uncle Bob”Robert Martin 引入了用OOP 开发软件的五条原
则,其目的是设计出更易于维护的高质量系统。无论是设计新应用程序,还是重构现有基
本代码,这些 SOLID 原则都成为开发人员的地图。
 
1. 单一职责原则
单一职责原则 (Single Responsibility Principle,SRP) 指出,每个方法或类应当有且仅有
一个改变的理由。这意味着每个方法或类应当做一件事情,或者只有一项职责。在所有的
SOLID 原则中,这是大多数开发人员感到最能完全理解的一条。严格来说,这也可能是违
反最频繁的一条原则了。
 
2. 开放/ 封闭原则
开放/封闭原则(Open/Close Principle,OCP)是指软件(方法、类等)应当开放扩充且关闭
修改。如果觉得它非常类似于继承的OOP 原则,那就对了。它们之间的关系非常密切。事
实上,在 .NET 中OCP 就是依赖于继承的。
OCP 的要点在于:作为开发人员,别人偶尔会向我们提供基类,偶尔也会为其他开发人
员生成基类框架,供其使用。这些使用者应当仅能使用这些基类,但不能对其进行修改。
这一点是必要的,因为其他使用者也可能依赖于由基类提供的功能。如果允许使用者修改
这些基类,可能会导致连锁反应,不仅会影响到应用程序中的各方面,还会影响到企业内
的应用程序。还有一个问题,使用者有时可能会收到基类的升级版本。使用者在升级之前,
必须找出一种方法用来处理其对该基类先前版本中所做的自定义。
于是,问题变为:“那么,如果我需要修改这个基类的工作方式,那应当怎么做呢?”
OCP 的另一部分中给出这一答案;基类应当开放,可进行扩充。在这里,扩充是指创建一
个由此基类继承而来的派生类,它可以扩充或重载基类功能,以提供使用者所需要的特定
功能。这样,使用者就能使用类的修改版本,而不会影响到类的其他使用者。使用者还可
以在将来更轻松地使用基类的升级版本,因为他们不用担心丢失自己的修改内容。
 
3. 里氏替换原则
继承对于OCP,就相当于多态性对于里氏替换原则(Liskov Substitution Principle,LSP)。
LSP 规定:用超类代替应用程序中使用的对象时,应当不会破坏应用程序。这通常也被称
为“契约式设计(design by contract)”。
回想前面的多态性示例,ComputePay 方法使用了Employee 类型的列表,其中Employee
就是基类型(超类型)。Salary、Hourly 和Seasonal 类都是从Employee 继承而来,因此它们
是Employee 的子类型。
根据LSP,即使已经将列表声明为Employee 的列表,也仍然可以用Salary、Hourly
和Seasonal 的具体实例来填充它。因为有了继承,它们都支持Employee 声明的相同契约(公
共的方法集或API)。应用程序可以对该列表进行迭代,并调用那些在列表中各个项目的
Employee 上定义的方法,不需要知道或特别关心它们都是什么类型。如果它们支持契约,
该调用就是合法的。
 
4. 接口分离原则
到目前为止,已经在示例中使用了基于类的继承,但还没有过多地讨论接口。回想一
下,接口就是在代码中定义的契约,而类同意实现这一契约。这份协议要求类来为接口中
定义的所有方法提供实现。至于如何实现方法,则由这个类来决定,只要它遵守契约,支
持接口中的定义即可。接口是.NET 中功能非常强大的功能;它们对继承和多态的支持方式
与类相同。
接口分离原则(Interface Segregation Principle,ISP)规定,不应当强制客户端依赖于其
不使用的接口。例如,银行系统可能有一个用于评估信用申请的服务。为便于讨论,假定
该服务不仅处理有质押信用(车船贷款、抵押),也处理无质押信用(信用卡、信用证、股票
信用额度)。如果正在开发一个客户端,用于帮助从事汽车代理的金融专员为其客户获得汽
车贷款,则只需要关注汽车贷款的申请即可,无需考虑有关这一服务的任何其他事情。如
果没有 ISP,应用程序可能必须了解其他方法。
尽管乍看起来这并没有什么,但它至少是增加了应用程序的复杂性,因为据以进行开
发的 API 中会有许多方法,远远超出所需要的。这样可能会导致混淆,调用错误的方法还
可能会导致潜在的错误。还有一种可能, API 中未被应用程序用到的部分可能会改变,而
这又会导致对终端的改变。这样,因为没用到、没想用、甚至是根本就不关心的一些功能,
而增加了应用程序的维护成本。这种情况还存在安全风险。该应用程序是专用于汽车贷款
的。如果不道德的开发人员利用这个过于庞大的 API 来允许利用这一申请担保其他类型的
信用,又该怎么办呢?这种问题的严重性就不仅仅是代码瘫痪、不可维护那么简单了。
这一问题的解决方案就是专门针对客户端的需要,为该服务创建几个更小的、更精细
的接口。对于该示例应用程序,专门设计一个针对汽车贷款的接口是比较适当的做法。应
用程序可以用同一实现访问同一个类,但这一次它使用了一个特定的接口,其中仅有实际
服务的一部分方法。这样就降低了复杂性,将应用程序与 API 其他部分的修改隔离开来,
还有助于堵塞安全漏洞。
 
5. 依赖倒置原则
在完美世界里,应用程序的组件之间没有耦合关系或绑定关系。开发人员也能够改变
自己希望改变的任何东西,而不需要担心在应用程序的其他地方出现缺陷,或者“不希望
存在的负面影响”。令人悲伤的是,我们并不是生活在完美世界里。因此,组件需要相互
绑定在一起,或者在某一点耦合,以构成实际应用程序。
依赖倒置原则(Dependency Inversion Principle,DIP)规定:代码应当取决于抽象概念,
而不是具体实现;这些抽象不应当依赖于细节;而细节应当依赖于抽象。类可能依赖于其
他类来执行其工作(Employee 服务可能依赖于数据访问组件向数据存储中保存和检索员工
信息)。但是,它们不应当依赖于该类的特定具体实现,而应当是它的抽象。也就是说,
Employee 服务不知道(或不关心)正在使用哪个具体的数据访问组件——只有它的抽象或代
码契约(或接口)支持那些用于保存和检索员工所需要的方法。
显然,这一概念会大大提高系统的灵活性。如果类只关心它们用于支持特定契约而不
是特定类型的组件,就可以快速而轻松地修改这些低级服务的功能,同时最大限度地降低
对系统其余部分的影响。在第6 章,还会看到如何利用这一概念来模拟这些依赖项,以进
行测试。有时,需要向类中提供这一低级服务的具体实现,以便这个类能够完成自己的工
作。最常见的做法,特别是在.NET 中使用TDD 的开发人员,就是依赖项注入(DI)模式。

SOLID 原则的更多相关文章

  1. 浅谈 SOLID 原则的具体使用

    SOLID 是面向对象设计5大重要原则的首字母缩写,当我们设计类和模块时,遵守 SOLID 原则可以让软件更加健壮和稳定.那么,什么是 SOLID 原则呢?本篇文章我将谈谈 SOLID 原则在软件开发 ...

  2. 【转】面向对象设计的SOLID原则

    S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...

  3. 面向对象设计的SOLID原则

    S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...

  4. 面向对象涉及SOLID原则

    S = Single Responsibility Principle 单一职责原则 O = Opened Closed Principle 开放闭合原则  L = Liscov Substituti ...

  5. TypeScript 中的 SOLID 原则

    下面的文章解释了正确使用 TypeScrip的 SOLID原则. 原文地址:https://samueleresca.net/2016/08/solid-principles-using-typesc ...

  6. 类设计的SOLID原则

    SOLID原则是面向对象范式的核心 单一职责原则(Single Responsible Principle, SRP):对于一个类,应该仅有一个引起它变化的原因.其基础是内聚,表示类完成单一功能的程度 ...

  7. 面向对象的SOLID原则白话篇

    面向对象的SOLID原则 简介 缩写 全称 中文 S The Single Responsibility Principle 单一责任原则 O The Open Closed Principle 开放 ...

  8. SOLID原则(OOD&OOP)

    SOLID原则是面向对象编程和面向对象设计的头五大原则.学习及应用这五大原则可以构建一个易于维护和扩展的应用程序,我们一起看看到底是那五大原则. S--单一责任原则(SRP) --Single Res ...

  9. SOLID原则 【转】

    S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写. 面向对象设计的原则 SRP  The Single ...

随机推荐

  1. MySQL使用rand函数实现随机数[转]

    如何写一个语句能一下更新几百条MYSQL数据! 需要测试MYSQL数据库,里面有一个上万条数据的数据库,如何写一个PHP文件一下每次更新几百条信息,我都是写一个循环一次更新一条信息,这样我知道用WHI ...

  2. 配置 apt-get cloudera 离线source(Cloudera Manager的源)

    配置 apt-get cloudera 离线source(Cloudera Manager的源) 创建/etc/apt/source.list.d/cloudera-manager.list文件,并在 ...

  3. .net(C#)操作文件的几种方法汇总

    .net(C#)操作文件的几种方法汇总 System.IO命名空间下类的用法:在System.IO名称空间中包含了用于文件输入输出的主要类.File:实用类,提供许多静态方法,用于移动.复制和删除文件 ...

  4. 我的VS2013中,用Ado.net给SQLParameter赋值的时候,当赋值null的时候,生成的sql语句是default

    /// <summary> /// 增加一条数据 /// </summary> public bool Add(Model.WechatDocuments model) { S ...

  5. JAVA栈实例—括号匹配

    import java.util.Stack; public class test { public static void main(String[] args){ System.out.print ...

  6. NewRelicAgent(CustomAnalyticEvent.cxx.o), building for iOS simulator, but linking in object file built for OSX, for architecture x8(botched)

    昨天遇到一个问题,在项目swift1.2适配swift2.0的过程中,修改完毕之后,运行报错如下: /Pods/NewRelicAgent/NewRelic_iOS_Agent_5.1.0/NewRe ...

  7. java获取常见文本文件的编码 解决乱码问题

    乱码问题的产生一般是,由字节流转字符流的时候,读文件的编码与文件的系统编码不一致造成的. 解决方式:先自动判断文件系统编码类型,然后读的时候用这个类型去读就ok了. 自动判断文件系统编码类型代码如下, ...

  8. hbuilder的aptana php插件无法提示命名空间之外函数和对象的解决办法

  9. websphere OSGi应用环境下服务调用saaj包加载问题分析报告

    websphere OSGi应用环境下服务调用saaj包加载问题分析报告 作者:bingjava 版权声明:本文为博主原创文章,转载请说明出处:http://www.cnblogs.com/bingj ...

  10. SQL Server性能优化(5)表设计时的注意事项

    一. 是否需要冗余列 现在一些项目的数据库设计中,为了提高查询速度,把基本表的一些列也放到了数据表里,导致数据冗余.例如在热表的数据库里,原始数据表Measure_Heat里加了如房间号,单元号,楼号 ...