为什么80%的码农都做不了架构师?>>>   

对象是对客观事物的抽象,类是对对象的抽象。对象是类的实例,类是对象的模版。

1.  单一责任原则(SRP)

它的意思是:“如果你可以在一个设备中实现所有的功能,你却不能这样做”。为什么呢?因为从长远来看它增加了很多的可管理性问题。

一个类有且只有一个职责。这并不意味着一个类就必须只有一个方法,但他们的目的必须          是一样的。如果有多个目的,那么你就必须拆分这个类,为什么呢?

  • 每个职责都是轴向变化;
  • 如果类包含多个职责,代码会变得耦合;

违反SRP原则的类层次结构

这里,Rectangle 类干了下面两件事:

  • 计算矩形面积;
  • 在界面上绘制矩形;

而且,有两个程序使用了 Rectangle 类:

  • 计算几何应用程序用这个类计算面积;
  • 图形程序用这个类在界面上绘制矩形;

这违反了SRP原则(单一职责原则)

后果就是,我在计算图形面积的时候,也必须去引用GUI资源。

可以按职责拆成两个类:

  • Rectangle:这个类定义 Area() 方法;
  • RectangleUI:这个把 Rectangle 类继承过来,定义 Draw() 方法。

总结:SPR 就是把东西分到不能再分了,再集中化管理和复用。方法也得分开,一个方法干一个活。

2.   开闭原则。(OCP)

当你穿外套的时候,不需要做开胸手术。

“模块应该对扩展开放,对更改关闭“  1. ”对扩展开放“,当需求改变时,我们可以最模块进行扩展,使其具有满足那些改变的新行为,使软件具有适应性和灵活性。2. ”对更改关闭“,当我们需要扩展新功能时,应编写新的代码,不应该修改原来的代码。

对于OCP原则来说,抽象是关键。例如:如果多个client依赖于一个具体的server,当server需要扩展新功能时,将导致所有的client都可能改动。解决方法就是抽象出来一个server,使client依赖这个抽象的server,仅说明哪些不易改变的一组服务,使其子类提供具体的实现和扩展,这样具体的实现和扩展的修改就不会影响到client。

对于OCP的另外一种理解是”封装可变性原则“(EVP)。其核心思想是”找到系统中的可变元素,将其封装起来“。EVP有两个要点:

1.  可变性不应散落在代码的各个角落,而应封装到一个类中。

2. 一种可变性不应该和另一种可变性混合在一起。

你允许什么发生改变,但不能让这个改变导致重新设计。OCP是面向对象设计的核心所在,但实际中滥用OCP也是错误的,正确的做法是仅对程序中呈现出频繁变化的部分进行抽象和封装。

3. 里氏替换原则。(LSP)

子类型必须能够替换它们的父类.

思想:继承必须确保父类所拥有的性质在子类中仍然成立,当一个子类的实例能够替换任何其父类的实例时,它们之间才具有is-a-kind-of-A关系.只有当一个子类(派生类)可以替换掉其父类(基类)而软件功能不受影响时,基类才能被复用,派生类也才能在基类的基础上增加新的行为.

其本质是在同一个继承体系中的对象应该有共同的行为特征.

例如:企鹅不属于鸟类,因为企鹅不会飞,所以企鹅不能继承鸟类。

Ostrich 都不应该继承 Bird 类,而应该从 Bird 中分出一个不会飞的类,由 Ostrich 继承。

   

  • 如果不遵循 LSP原则,类继承就会混乱。如果子类实例被作为参数传递给方法,后果难以预测。
  • 如果不遵循 LSP原则,基于父类编写的单元测试代码将无法成功运行子类。

这个原则是对继承的一个约束,也就是说,继承中子类严格满足"is a "的关系.这里我个人有深刻的体会.尤其是在看别人的UML图的时候. 
对你帮助很大.当你看到一个继承的时候.要习惯性的把他的父类和子类看成一个整体.这样会有助于你去理解各个类之间的关系.因为根据 
里氏代换原则.父类出现的地方子类也可以出现.

比如我们再看工厂模式的时候,你看到有的书上简单工厂类关联着运算父类.有的书上是关联着运算类的子类.其实仔细想想他们都没有错, 
父类和子类的关联都是一样的,父类能出现的地方,子类就可以出现.

4. 接口分离原则(ISP)。

提供尽可能”小“的,单独的接口,而不是提供一个大的接口。

思想:多个和客户相关的接口要好于一个通用接口.如果一个类有几个使用者,与其让这个类再如所有使用这需要使用的所有方法,还不如为每个使用者创建一个特定接口,并让该类分别实现这些接口.。不要让接口中有和该接口功能无关的多余的方法。

如上图所示,类A依赖接口I中方法1\方法2\方法3, 类B是对类A依赖的实现, 类C依赖于接口I中的方法方法1\方法4\方法5, 类D是对类C依赖的实现.对于类B和类D中都存在用不到的方法, 但是由于实现了接口I,所以需要实现这些不用的方法。可以发现接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用,实现类中都必须去实现这些方法,如类B中方法4和方法5,类D中方法2和方法3,显然这样的设计不适用..

接口隔离原则即尽量细化接口,接口中的方法尽量少,为各个类建立专用的接口,而不是试图去建立一个庞大而臃肿的接口提供所有依赖于他的类去调用.

说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。

其一,单一职责原则原注重的是职责,而接口隔离原则注重对接口依赖的隔离.

其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建.

5.   依赖倒置原则。(DIP)

思想:高层模块不应该依赖低层模块,二者都应该依赖于抽象.

换句话说:要依赖于抽象,而不要依赖于具体实现;高层是功能和策略,低层是具体实现;编程程序语言就是需要针对接口编程而不要针对实现编程.

就像我们造汽车,我们不能根据某台汽车去造轮子,我们应该按照一种标准去造,如果按照某台汽车去造轮子,轮子坏了,难道要换新车?

例如:

现在司机eastmount不仅要开奔驰车,还要开宝马车,又该怎么实现呢?自定义宝马汽车类BMW,但是不能开,因为eastmount没有开宝马车的方法,出现的问题就是:

司机类和奔驰车类之间是一个紧耦合关系,这导致了系统的可维护性大大降低,增加新的车类如宝马BWM汽车就需要修改司机类drive()方法,这不是稳定性而是易变的.被依赖者的变化竟然让依赖者来承担修改的代价,所以可以通过依赖倒置原则实现.

如下图所示,通过建立两个接口IDriver和ICar,分别定义了司机的职能就是驾驶汽车,通过drive()方法实现;汽车的职能就是运行,通过run()方法实现.

总结:

1. 单一指责原则规范了类和方法的功能必须单一。

即:将不同的功能隔离开来,不要都混合到一个类中。

2. 开闭原则要求(类,模块,函数等)应该对扩展开放,对修改关闭。

即,如果遇到需求变化,要通过添加新的类来实现,而不是修改现有的代码。这一点也符合单一职责原则。

3. 里氏替换原则规定了继承。子类可以完全替换父类。

4. 接口隔离原则要求接口不要臃肿。

添加新功能时,要增加一个新接口,而不是修改已有的接口,禁止出现“胖接口”。符合单一职责原则和开放封闭原则。

5. 依赖倒置原则规定要面向接口编程。

具体依赖于抽象,而非抽象依赖与具体。即,要把不同子类的相同功能抽象出来,依赖与这个抽象,而不是依赖于具体的子类。

我们讨论了5个设计原则,最重要的是OCP,其他四个都附属于开闭原则,违背其他四个原则都直接或间接违背OCP。

solid原则的目的就是为了提取可变的部分封装,提高代码可复用性。

其他两个原则:

5、迪米特法则(最少知道原则)(Demeter Principle)

就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。

最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

class Girl{//女生
}

老师要班长点名

class Teacher{//让班长点名public function Commond($groupLeader){//老师却和女生有关系了。不合理$girls = array();//添加女生都放老师类里面了。如果我要再加一个,就要修改老师类,耦合度太高,代码重用太低for($i = 0; $i < 20; $i++){$girls[] = new Girl();}return $groupLeader -> countGirls($girls);}}class GroupLeader{//班长public function countGirls($girls){return sizeof($girls);}}

迪米特原则:

class Teacher{public function Commond($groupLeader){//只是告诉班长,你点一下名字。不用去和女生有关系return $groupLeader -> countGirls();}}class GroupLeader{private $_girls = array();//班长public function countGirls(){return sizeof($this ->_girls);}public function addGirl($girl){//可以独立添加女孩,而不用修改类$this -> _girls = $girl;}}$groupLeader = new GroupLeader();//如果换成了男孩,也不用修改班长和老师类
$groupLeader -> addGirl(new Girl());
$groupLeader -> addGirl(new Girl());
$groupLeader -> addGirl(new Girl());$teacher = new Teacher();
//如果换了班长也不用修改老师类
$teacher -> Commond(new $groupLeader());//修改后代码的可重用性可见

用迪米特原则的设计模式:外观模式和中介者模式

6、合成复用原则(Composite Reuse Principle)

原则是尽量首先使用合成/聚合的方式,而不是使用继承

单一职责原则告诉我们实现类要职责单一;

里氏替换原则告诉我们不要破坏继承体系;

依赖倒置原则告诉我们要面向接口编程;

接口隔离原则告诉我们在设计接口的时候要精简单一;

迪米特法则告诉我们要降低耦合(类与类之间的调用关系)。

而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。

转载于:https://my.oschina.net/shyl/blog/525465

SOLID面向对象模式浅析相关推荐

  1. php面向对象之策略模式,php策略模式的学习--引自《深入php面向对象模式与实践》...

    #策略(Strategy)模式 #定义抽象类 Lesson abstract class Lesson{ private $duration; private $coststrategy;#定义属性 ...

  2. 正则表达式贪婪模式、懒惰模式与独占模式浅析

    正则表达式贪婪模式.懒惰模式与独占模式浅析 一.正则表达式引擎: 正则表达式的执行,是由正则表达式引擎编译执行的,正则表达式引擎分为DFA(Deterministic finite automaton ...

  3. 虚拟机的三种可选模式:桥接模式、NAT模式、主机模式浅析

    一.问题场景 在配置虚拟机的时候,往往有三种可供选择的网络模式:桥接模式.NAT模式.主机模式浅析.查阅了有关的资料,在下面对这三种模式做一下区分. 二.区别 假设在网段为 192.168.100.x ...

  4. 中国SNS网站盈利模式浅析及探讨

    早在1997年,国外就有人根据哈佛大学心理学教授Stanley Milgram(1934~1983)创立的六度分割理论(Six Degrees of Separation)创立了第一个SNS(社交)网 ...

  5. python 面向对象 私有化浅析

    · 前言 近几日,学校的python课程学到了面向对象这一块内容,在做作业的时候看到老师布置的内容有关于getters.setters两个方法的使用操作:可是老师既没讲清楚,度娘搜到的结果也模模糊糊, ...

  6. 构造函数 + 原型链继承 + 临摹面向对象模式的canvas动画框架

    感谢谢帅shawn分享的canvas动画框架,我再来分一次 //动画框架 http://neekey.net/blog/2011/05/11/canvas-%E7%AE%80%E5%8D%95%E5% ...

  7. JavaScript面向对象编程浅析

    JavaScript面向对象编程及设计模式 JavaScript面向对象编程及设计模式 一.面向对象编程 1.简述 2.面向对象编程特点 3.封装 4.this 5.call和apply 6.new ...

  8. Epoll两种模式浅析(ET or LT)

    linux异步IO浅析  http://hi.baidu.com/_kouu/blog/item/e225f67b337841f42f73b341.html epoll有两种模式,Edge Trigg ...

  9. Java 门面模式 浅析

    Java中的门面模式,一般来说他的用途是隐藏一些不希望用户看到的东西,比如方法,变量,并且这些变量是不能够设置成私有的,因为在系统内部有些地方需要调用.在Tomcat的HttpServletReque ...

最新文章

  1. Centos6.5安装python2.7与pip
  2. 央行无意放宽松,7月贷款仍有可能吃紧
  3. 《看聊天记录都学不会Python到游戏实战?太菜了吧》(8)我们开始做一个数字小游戏吧
  4. matlab figure 嵌套,操作Matlab的Figure窗口(一)
  5. react的一些概念
  6. Ubuntu18.04下QSqlDatabase: QMYSQL driver not loaded
  7. 数据驱动的智慧城市 中兴通讯推进“沈阳模式”落地
  8. 特征点检测-SIFT
  9. 处理网页上的字符溢出的方法
  10. 使用Spring注解获取配置文件信息
  11. 微信小程序TabBar的使用
  12. 惠普服务器不进系统,HP服务器无法启动
  13. 解决ie浏览器兼容ES6语法问题
  14. AirPods Pro 卡顿或突然没声音的原因之一
  15. 折腾小记(***+云盘选择+个人环境配置)
  16. (六)springMvc 和 mybatis 整合
  17. 能耗指标与数据中心规模-孙长青
  18. 关于dijkstra算法的个人总结
  19. 顶尖学者介绍 | 抑郁领域研究Top1-5的大牛们都是谁?快来看!
  20. Mockito 框架用于单元测试

热门文章

  1. 强化学习应用于组合优化问题
  2. SAP QA32 做使用决策系统报错:分类数据的不一致性=交易终止
  3. 机器学习Basics-第十一期-循环神经网络RNN
  4. 一文了解机器学习中的交叉熵
  5. 使用机器学习方法预测IBM员工流失数据模型
  6. 2018中国移动机器人行业十大热词
  7. torch.tensordot()介绍
  8. windows安装visual studio code并配置latex并编写latex论文
  9. 2022年值得关注的8个人工智能趋势
  10. 关于自动驾驶, Mobileye 的 14 个最新观点