面向对象的SOLID原则白话篇
面向对象的SOLID原则
简介
| 缩写 | 全称 | 中文 |
|---|---|---|
| S | The Single Responsibility Principle | 单一责任原则 |
| O | The Open Closed Principle | 开放封闭原则 |
| L | Liskov Substitution Principle | 里氏替换原则 |
| I | The Interface Segregation Principle | 接口分离原则 |
| D | The Dependency Inversion Principle | 依赖倒置原则 |
单一职责原则
一个类只应承担一种责任。换句话说,让一个类只做一件事。如果需要承担更多的工作,那么分解这个类。
举例
订单和账单上都有流水号、业务时间等字段。如果只用一个类表达,赋予其双重职责,后果:
- 特有属性和共有属性相互掺杂,难以理解;
- 修改一个场景可能会影响另一个场景。
正确的做法是拆成两个独立的类。
开放封闭原则
实体应该对扩展是开放的,对修改是封闭的。即,可扩展(extension),不可修改(modification)。
举例
一个商户接入了多个付款方式,支付宝和微信支付,如果将调用支付API的类写成:
public class PayHandler {
public Result<T> pay(Param param) {
if(param.getType() == "ALIPAY") {
// 支付宝付款调用
...
} else if(param.getType() == "WeChatPay") {
// 微信支付付款调用
...
}
}
}
那么每次新加一种支付方式,或者修改原有的其中一种支付方式,都要修改PayHandler这个类,可能会影响现有代码。
比较好的做法是将不同的行为(支付方式)抽象,如下:
public class PayHandler {
private Map<String, PayProcessor> processors;
public Result<T> pay(Param param) {
PayProcessor payProcessor = processors.get(param.getType());
// 异常处理略
return payProcessor.handle(param);
}
}
interface PayProcessor {
Result<T> handle(Param param);
}
public class AlipayProcessor implements PayProcessor {
...
}
public class WeChatPayProcessor implements PayProcessor {
...
}
这样,新增支付方式只需要新增类,如果使用的是spring等容器,在xml配置对应key-value关系即可;修改已有的支付方式只需要修改对应的类。最大化地避免了对已有实体的修改。
里式替换原则
一个对象在其出现的任何地方,都可以用子类实例做替换,并且不会导致程序的错误。换句话说,当子类可以在任意地方替换基类且软件功能不受影响时,这种继承关系的建模才是合理的。
举例
经典的例子: 正方形不是长方形的子类。原因是正方形多了一个属性“长 == 宽”。这时,对正方形类设置不同的长和宽,计算面积的结果是最后设置那项的平方,而不是长*宽,从而发生了与长方形不一致的行为。如果程序依赖了长方形的面积计算方式,并使用正方形替换了长方形,实际表现与预期不符。
扩展
不能用继承关系(is-a),但可以用委派关系(has-a)表达。上例中,可以使用正方形类包装一个长方形类。或者,将正方形和长方形作进一步抽象,使用共有的抽象类。
逸闻
“里氏”指的是芭芭拉·利斯科夫(Barbara Liskov,1939年-),是美国第一个计算机科学女博士,图灵奖、冯诺依曼奖得主,参与设计并实现了OOP语言CLU,而CLU语言对现代主流语言C++/Java/Python/Ruby/C#都有深远影响。其项目中提炼出来的数据抽象思想,已成为软件工程中最重要的精髓之一。(来源: 互动百科)
接口分离原则
客户(client)不应被强迫依赖它不使用的方法。即,一个类实现的接口中,包含了它不需要的方法。将接口拆分成更小和更具体的接口,有助于解耦,从而更容易重构、更改。
举例
仍以商家接入移动支付API的场景举例,支付宝支持收费和退费;微信接口只支持收费。
interface PayChannel {
void charge();
void refund();
}
class AlipayChannel implements PayChannel {
public void charge() {
...
}
public void refund() {
...
}
}
class WeChatChannel implements payChannel {
public void charge() {
...
}
public void refund() {
// 没有任何代码
}
}
第二种支付渠道,根本没有退款的功能,但是由于实现了PayChannel,又不得不将refund()实现成了空方法。那么,在调用中,这个方法是可以调用的,实际上什么都没有做!
改进
将PayChannel拆成各包含一个方法的两个接口PayableChannel和RefundableChannel。
依赖倒置原则
- 高层次的模块不应依赖低层次的模块,他们都应该依赖于抽象。
- 抽象不应依赖于具体实现,具体实现应依赖抽象。
实际上,依赖倒置是实现开闭原则的方法。
举例
开闭原则的场景仍然可以说明这个问题。以下换一种表现形式。
public class PayHandler {
public Result<T> pay(Param param) {
if(param.getType() == "ALIPAY") {
AlipayProcessor processor = new AlipayProcessor();
processor.hander(param);
...
} else if(param.getType() == "WeChatPay") {
WeChatPayProcessor processor = new WeChatPayProcessor();
processor.hander(param);
...
}
}
}
public class AlipayProcessor { ... }
public class WeChatPayProcessor { ... }
这种实现方式,PayHandler的功能(高层次模块)依赖了两个支付Processor(低层次模块)的实现。
扩展:IOC和DI
控制反转(IOC)和依赖注入(DI)是Spring中最重要的核心概念之一,而两者实际上是一体两面的。
- 依赖注入
- 一个类依赖另一个类的功能,那么就通过注入,如构造器、setter方法等,将这个类的实例引入。
- 侧重于实现。
- 控制反转
- 创建实例的控制权由一个实例的代码剥离到IOC容器控制,如xml配置中。
- 侧重于原理。
- 反转了什么:原先是由类本身去创建另一个类,控制反转后变成了被动等待这个类的注入。
后记
网络上很多文章中关于SOLID的介绍,语句都不通顺,徒增理解难度。如果对基本释义仍不能领会,可以参考 英文WIKI。
面向对象的SOLID原则白话篇的更多相关文章
- 面向对象涉及SOLID原则
S = Single Responsibility Principle 单一职责原则 O = Opened Closed Principle 开放闭合原则 L = Liscov Substituti ...
- 在net中json序列化与反序列化 面向对象六大原则 (第一篇) 一步一步带你了解linq to Object 10分钟浅谈泛型协变与逆变
在net中json序列化与反序列化 准备好饮料,我们一起来玩玩JSON,什么是Json:一种数据表示形式,JSON:JavaScript Object Notation对象表示法 Json语法规则 ...
- 【转】面向对象设计的SOLID原则
S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...
- 面向对象设计的SOLID原则
S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...
- 面向对象设计SOLID五大原则
转载自:码农社区,http://w3croom.com/read.php?tid-4522.html 今天我给大家带来的是面向对象设计SOLID五大原则的经典解说. 我们知道,面向对象对于 ...
- PHP 进阶篇:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 (麦子学员 第三阶段)
以下是进阶篇的内容:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 ================================== ...
- OOD 面向对象面试干货分享| 面向对象设计的SOLID原则
S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. 简写 全拼 中文翻译 SRP The Single Res ...
- 面向对象SOLID原则的自我理解
S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写.面向对象设计的原则SRP The Single Res ...
- 浅谈 SOLID 原则的具体使用
SOLID 是面向对象设计5大重要原则的首字母缩写,当我们设计类和模块时,遵守 SOLID 原则可以让软件更加健壮和稳定.那么,什么是 SOLID 原则呢?本篇文章我将谈谈 SOLID 原则在软件开发 ...
随机推荐
- Linux命令之初出茅庐
此处讲解常用到的参数选项: ls 是列出文件的意思 ls -a ,查看所有文件包含隐藏文件 ls -l ,查看与文件相关的所有属性信息 ls -i ,查看文件的inode信息 ls -h,按照更为容易 ...
- hadoop单机环境搭建
[在此处输入文章标题] Hadoop单机搭建 1. 工具准备 1) Hadoop Linux安装包 2) VMware虚拟机 3) Java Linux安装包 4) Window 电脑一台 2. 开始 ...
- OC类的介绍
类的本质 类的本质其实也是一个对象(类对象) 类对象 类对象再程序运行时一直存在 类对象是一种数据结构,存储类的基本信息:类大小,类名称,类的版本以及消息与函数的映射表等 类对象所保存的信息在程序编译 ...
- html页面顶部出现一段空白,检查控制台发现body 下出现字符,原因及解决办法
html页面顶部出现一段空白,检查控制台发现body 下出现字符,原因及解决办法 分析: 原来是页面编码时增加了BOM,此页面后端数据主要是PHP语言,对PHP来讲PHP在设计时 ...
- hdu2159 FATE 经典二维背包
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路: 定义ans存当前满足条件的消耗的最小的忍耐值(满足条件的忍耐值为在当前消耗的忍耐值的情况 ...
- Linux安装jdk7开发环境
1.官网 下载jdk7版本 地址: http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-jav ...
- Android 模块化探索与实践
首发于<程序员>杂志五月刊 一.前言 万维网发明人 Tim Berners-Lee 谈到设计原理时说过:"简单性和模块化是软件工程的基石:分布式和容错性是互联网的生命." ...
- springcloud(四):熔断器Hystrix
说起springcloud熔断让我想起了去年股市中的熔断,多次痛的领悟,随意实施的熔断对整个系统的影响是灾难性的,好了接下来我们还是说正事. 熔断器 雪崩效应 在微服务架构中通常会有多个服务层调用,基 ...
- MyBatis源码解读(4)——SqlSession(上)
在上一篇博客中提到MyBatis是如何实现代理类MapperProxy,并抛出了一个问题--是怎么执行一个具体的sql语句的,在文末中提到了MapperMethod的execute采用命令模式来判断是 ...
- How To Configure VMware fencing using fence_vmware_soap in RHEL High Availability Add On(RHEL Pacemaker中配置STONITH)
本文主要简单介绍一下如何在RHEL 7 Pacemaker中配置一个fence_vmware_soap类型的STONITH设备(仅供测试学习). STONITH是Shoot-The-Other-Nod ...