SOLID设计原则和我的一点个人感悟
什么是solid 为什么需要它
技术可以落后,思想必须先进。一栋好的大楼,并非是表面看起来,砖、泥... ,如果我们以普通人的眼光去看待这么一栋楼,使用原始材料一点一点搭建起来,那将是无法想象的糟糕。与程序一样,如果没有好的设计以及各个角色之间的相互协调,那么你的产品也是一塌糊涂。
越庞大、复杂的项目越需要巧妙的设计,同时程序还需要保证可维护性和可扩展性,那程序怎么设计才能算得上是满足条件呢?在程序设计领域,有个SOLID (单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)
设计原则,经过反复的试验,它使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。
单一原则 | 单一功能 (SRP)
这个比较简单,一个对象应该只包含一个职责,并且该职责被完整地封装在一个类中。(甲类负责两个不同的职责:职责A,职责B。当由于职责A需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责B功能发生故障。也就是说职责A和B被耦合在了一起”)。
开放封闭原则(OCP)
实体应该对扩展是开放的,对修改是封闭的。即可扩展(extension),不可修改(modification)
例如:
一开始可能是这样
class VIPCenter {
public function serviceVIP()
{
if ($user instanceof SlumDogVIP) {
// 活动vip
} elseif ($user instanceof RealVIP) {
// 真实vip
}
}
}
改进后
class User {
public $index;
/**
* User constructor.
*/
public function __construct($index)
{
$this->index = $index;
}
}
class VIPCenter {
private $providers = [];
/**
* VIPCenter constructor.
* @param array $providers
*/
public function __construct()
{
$this->providers[] = new RealVIPServiceProvider();
$this->providers[] = new SlumDogVIPServiceProvider();
}
public function serviceVIP(User $user)
{
$this->providers[$user->index]->service($user);
}
}
interface ServiceProvider {
public function service(User $user);
}
class SlumDogVIPServiceProvider implements ServiceProvider {
public function service(User $user)
{
// TODO: Implement service() method.
echo '领取的vip';
}
}
class RealVIPServiceProvider implements ServiceProvider {
public function service(User $user)
{
// TODO: Implement service() method.
echo '真充钱了的';
}
}
$vip = new VIPCenter();
$vip->serviceVIP(new User(1));
但需要增加新的条件,我不必去修改里面的逻辑,我只需要增加对应实现
里氏替换原则(LSP)
任何基类可以出现的地方,子类一定可以出现。但是由此衍生几种问题
- 继承是入侵性的 子类必须拥有父类的方法,降低了类的灵活度 父类对子类进行了一些约束
- 增强了耦合度 当对父类代码进行修改时 必须考虑到对子类的影响
- 里氏替换原则对继承进行了规则约束
- 子类必须实现父类的抽象方法 但是不得重写父类的方法
- 子类实现父类 参数必须放大
接口隔离原则(ISP)
在设计中需要避免不需要的依赖,拆分臃肿接口,对接口进行隔离,例如:电话接口只需要接电话和打电话 不需要通讯录,通讯录就需要独立出来接口,有点类似单一原则,但是单一原则更多的是约束类,接口隔离更注重对接口依赖的隔离。
依赖倒置原则(DIP)
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
附 迪米特法则
一个对象应该对其他对象保持最少的了解。
例如:人可以买楼,但是不需要直接和楼盘打交道,只需要和中介发生关系,主要就是增加桥接类,要权衡使用 否则会出现很多用来桥接的类
个人感悟
在初入开发行业时,没什么项目经验,看很多的设计模式都是云里雾里,以为开发什么都可以用 MVC
来解决,那么多设计模式意义何在,如今重头再看,不禁佩服这些作者的远见卓识,再次认为自己是来凑人数的。
在快速发展的软件开发领域,我们还是抱着独行侠剑客的思维,很快将会被淘汰,闭门造车不如站在巨人的肩上。基本上一个大型的编程系统产品的开发成本会是单个的简单程序的9倍,随着项目的不断推进,设计的失误会导致项目出现各种意外,开发人员不仅仅面对新的需求,跟要面临着陈旧过时的威胁,开发者大多都是乐观主义者,我们往往会认为“这次肯定能运行”或者是“我已经找出了最后一个bug”,当然,这并非是怪罪于开发人员,"只缘身在此山中" 我们大家都是从看着地面开发慢慢变成看着远处开发。
说到这还得说我初入行的一个疑惑的问题: 人多就能解决项目问题吗?
一开始项目开发进度推进慢,我老是觉得是人手不够的原因,回想当时的人员和管理,感觉望着地面开发都快踩到自己脚了,还在埋怨人员的问题,哈哈。 这次课上到这先结束了,下次再开课。
- 简单易学的机器学习算法——SVD奇异值分解
- AngularJS源码分析之依赖注入$injector
- 使用yield进行异步流程控制
- 【Java提高十七】Set接口集合详解
- 如何科学地蹭热点:用python爬虫获取热门微博评论并进行情感分析
- 使用ETag进行session的降级
- 关于oracle中的反连接(r3笔记第95天)
- 用Python爬取网易云音乐的用户评论文本
- grunt任务之seajs模块打包
- 【Java提高十八】Map接口集合详解
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(五)讲一下maven
- Thinking in React
- 【Java提高十六】集合List接口详解
- JS的内建函数reduce
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法