- 单一责任原则(SRP)
The Single Responsibility Principle
引用老外的一张经典图解:
单一职责原则要求“一个类只能有一个职责”,引起这个类变化的唯一原因只能是这个职责。当类有多个职责的时候,应当把其他的职责分离出去,分别创建类来完成。
例如:
类Modem实现了调制解调器的功能,但却实现了两个职责(当然你也可以说是四个职责,这个是按照应用场景来分的),连接的建立和终端,数据的传输和接收。那么问题来了,如果要修改数据传输方式的话,就需要修改Modem类,那么所有依赖Modem的元素都需要修改。上图的解决方法是重构Modem,从中抽出两个接口,Connection专门负责连接,DataChannel负责数据传输。最后有ModemImplementation实现这两个接口。
- 开闭原则。(OCP)
The Open Closed Principle
当你穿外套的时候,不需要做开胸手术。
“模块应该对扩展开放,对更改关闭“ 1. ”对扩展开放“,当需求改变时,我们可以最模块进行扩展,使其具有满足那些改变的新行为,使软件具有适应性和灵活性。2. ”对更改关闭“,当我们需要扩展新功能时,应编写新的代码,不应该修改原来的代码。
对于OCP原则来说,抽象是关键。例如:如果多个client依赖于一个具体的server,当server需要扩展新功能时,将导致所有的client都可能改动。解决方法就是抽象出来一个server,使client依赖这个抽象的server,仅说明哪些不易改变的一组服务,使其子类提供具体的实现和扩展,这样具体的实现和扩展的修改就不会影响到client。
对于OCP的另外一种理解是”封装可变性原则“(EVP)。其核心思想是”找到系统中的可变元素,将其封装起来“。EVP有两个要点:
1. 可变性不应散落在代码的各个角落,而应封装到一个类中。
2. 一种可变性不应该和另一种可变性混合在一起。
你允许什么发生改变,但不能让这个改变导致重新设计。OCP是面向对象设计的核心所在,但实际中滥用OCP也是错误的,正确的做法是仅对程序中呈现出频繁变化的部分进行抽象和封装。
- 里氏替换原则。(LSP)
The Liskov Substitution Principle
真鸭子和玩具鸭子都抽象鸭子,但是玩具鸭子需要电池,这就是个错误的抽象。
思想:继承必须确保父类所拥有的性质在子类中仍然成立,当一个子类的实例能够替换任何其父类的实例时,它们之间才具有is-a-kind-of-A关系.只有当一个子类(派生类)可以替换掉其父类(基类)而软件功能不受影响时,基类才能被复用,派生类也才能在基类的基础上增加新的行为.
其本质是在同一个继承体系中的对象应该有共同的行为特征.
例如:企鹅不属于鸟类,因为企鹅不会飞,所以企鹅不能继承鸟类。
- 接口分离原则(ISP)。
The Interface Segregation Principle
提供尽可能”小“的,单独的接口,而不是提供一个大的接口。
思想:多个和客户相关的接口要好于一个通用接口.如果一个类有几个使用者,与其让这个类再如所有使用这需要使用的所有方法,还不如为每个使用者创建一个特定接口,并让该类分别实现这些接口.。不要让接口中有和该接口功能无关的多余的方法。
如上图所示,类A依赖接口I中方法1\方法2\方法3, 类B是对类A依赖的实现, 类C依赖于接口I中的方法方法1\方法4\方法5, 类D是对类C依赖的实现.对于类B和类D中都存在用不到的方法, 但是由于实现了接口I,所以需要实现这些不用的方法。可以发现接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用,实现类中都必须去实现这些方法,如类B中方法4和方法5,类D中方法2和方法3,显然这样的设计不适用..
接口隔离原则即尽量细化接口,接口中的方法尽量少,为各个类建立专用的接口,而不是试图去建立一个庞大而臃肿的接口提供所有依赖于他的类去调用.
说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。
其一,单一职责原则原注重的是职责,而接口隔离原则注重对接口依赖的隔离.
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建.
- 依赖倒置原则。(DIP)
The Dependency Inversion Principle
思想:高层模块不应该依赖低层模块,二者都应该依赖于抽象.
换句话说:要依赖于抽象,而不要依赖于具体实现;高层是功能和策略,低层是具体实现;编程程序语言就是需要针对接口编程而不要针对实现编程.
1.高层模块只应该包含重要的业务模型和策略选择
2.低层模块则是不同业务和策略的实现
3.高层抽象不依赖高层和底层模块的具体实现,最多依赖低层的抽象
4.低层抽象和实现也只依赖于高层抽象
例如:
现在司机eastmount不仅要开奔驰车,还要开宝马车,又该怎么实现呢?自定义宝马汽车类BMW,但是不能开,因为eastmount没有开宝马车的方法,出现的问题就是:
司机类和奔驰车类之间是一个紧耦合关系,这导致了系统的可维护性大大降低,增加新的车类如宝马BWM汽车就需要修改司机类drive()方法,这不是稳定性而是易变的.被依赖者的变化竟然让依赖者来承担修改的代价,所以可以通过依赖倒置原则实现.
如下图所示,通过建立两个接口IDriver和ICar,分别定义了司机的职能就是驾驶汽车,通过drive()方法实现;汽车的职能就是运行,通过run()方法实现.
我们讨论了5个设计原则,最重要的是OCP,其他四个都附属于开闭原则,违背其他四个原则都直接或间接违背OCP。
SOLID面向对象模式浅析
时间: 2024-10-10 21:02:31
SOLID面向对象模式浅析的相关文章
结构化方法与面向对象方法浅析
结构化方法与面向对象方法浅析 在目前的软件开发领域,结构化方法和面向对象方法是两种比较流行的方法.在过去两年多时间里,我们也对这两种方法进行了学习和实践,下面谈一谈自己对这两种方法的理解. 结构化方法 结构化方法是一种比较传统的软件系统开发方法,主要思想是分析问题确定软件功能,之后将整体功能划分成不同的功能模块,然后将实现之后的模块拼接结合在一起,是一个先分再和的过程.功能分解可以使软件条理清晰,将复杂的问题拆分成相对简单的小问题也便于实现. 结构化方法注重算法和数据,程序过程可以看
VMware Workstation之虚拟网络的三种连接模式浅析
刚开始接触VMware Workstation做实验时常常为选择哪种网络连接模式而苦恼. 有时候老师说选择NAT,有时候建议桥接,还有时会要求仅主机. 唉,真是老师说什么就是什么. 既然不懂那就乖乖跟着老师屁股后面,老师怎么要求我们就怎么做,一点自己发挥的余地都不能有. 机械的跟着老师做了这么多实验,吃了这么多的苦楚,大家有没有想过,我们搭建实验环境为什么要选择不同的网络连接模式,为什么我们实验的其他部署都对了,但就是因为忽略了连接模式这个小差错而导致各种报错,为什么老师一直说实验前的ping通
JavaScript (JS) 面向对象编程 浅析 (含对象、函数原型链解析)
1. 构造函数原型对象:prototype ① 构造函数独立创建对象,消耗性能 function Person(name) { this.name = name; this.sayHello = function () { console.log("Hello,my name is " + this.name) } } var P1 = new Person("Tom"); var P2 = new Person("Jim"); P1.sayHe
Node.js 异步模式浅析
注:此文是node.js实战读后的总结. 在平常的脚本语言中都是同步进行的,比如php,服务器处理多个请求的方法就是并行这些脚本.多任务处理,多线程等等.但是这种处理方式也有一个问题:每一个进程或者线程都会耗费大量的系统资源.如果有一种方法可以最大化的利用CPU的计算能力和可用内存以减少资源浪费那就极好了.这样,我们的node.js就应运而生了. 上一个node.js最简单的异步编程案例: 1 var fs = require('fs'); 2 3 var file; 4 5 fs.open(
设计模式——工厂模式浅析
简单工厂模式(simple factory)是类的创建模式,又叫静态工厂方法(static factory method)模式. 简单工厂模式就是由一个工厂类根据传入的参数决定创建哪一种的产品类. 有4个角色 工厂类角色:是具体产品类角色直接调用者. 抽象产品角色:接口或抽象类,负责具体产品角色的定义,及与客户端的交互. 具体产品角色:被工厂类创建的对象,也是客户端实际操作对象. 客户端:调用工厂类产生实例,并调用实例的方法进行相应工作. public interface people{ pub
Android开发中MVP模式浅析
目前为止,MVP的使用还没有一个标准,在此先记录一下目前学习到的一些Android中使用MVP的知识. 按传统的方式开发,经常会使Activity中混杂着UI交互,业务逻辑等流程.而MVP模式能巧妙的解决这个问题.先直接上一个小例子吧. /** * 定义一个对UI组件进行操作的接口,让Activity实现这个接口 * @author Quinn * @date 2015-5-9 */ public interface LoginView { public void showProgress();
享元模式浅析
源码面前,了无秘密. 1 package com.xiaolu.flyweightdemotest; 2 3 4 import org.junit.Assert; 5 import org.junit.Test; 6 7 import com.xiaolu.flyweight.FlyweigthtFactory; 8 import com.xiaolu.flyweight.IChess; 9 10 11 12 /*** 13 * 享元模式:flyweight有轻量的意思.享元即共享.这里的轻量到
标准IDispose模式浅析
position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流
C语言中文件打开模式(r/w/a/r+/w+/a+/rb/wb/ab/rb+/wb+/ab+)浅析
C语言文件打开模式浅析 在C语言的文件操作语法中,打开文件文件有以下12种模式,如下图: 打开模式 只可以读 只可以写 读写兼备 文本模式 r w a r+ w+ a+ 二进制模式 rb wb ab rb+ (r+b) wb+ (w+b) ab+ (a+b) 其中,二进制模式与文本模式操作相似,只不过是以二进制流的形式读写而已,下面以文本模式为例分析: 1."r" 模式: 1.1 打开文件进行“只读”操作,即只能从文件读取内容. 1.2 若欲操作的文件不存在,则打开