转载说明:
感谢原作者吕震宇老师的分享。
原文参考链接:https://www.cnblogs.com/zhenyulu/category/6930.html?
本次转载只用于个人学习使用,并不涉及商业用途。转载请声明作者以及出处。


文章目录

  • 面向对象设计的六大设计原则表
  • 一、 "开放-封闭"原则(OCP)
  • 二、 里氏代换原则(LSP)
    • 一个违反LSP的简单例子(长方形和正方形)
      • 1. Rectangle和Square类的定义
      • 2. Square和Rectangle的具体实现
      • 3. 错误示例的UML图
      • 4. 代码重构
      • 5. 重构后的UML图
  • 三、 依赖倒置原则(DIP)
    • 1. DIP的定义解读
    • 2. 举一个反面例子及解决办法
      • 反面例子:
      • 解决办法一:
      • 解决方法二:
    • 四、 接口隔离原则(ISP)
    • 1. 接口隔离原则的内容解读
    • 2. 实现方法
  • 五、 合成/聚合复用原则(CARP)
    • 1. 合成、聚合复用原则的解读
    • 2. 区分"Has-A"与"Is-A"
      • 1. 错误示例
      • 2. 解决办法
  • 六、 迪米特法则(LoD)
    • 1. 迪米特法则(LoD)的内容解读
    • 2. 迪米特法则与设计模式
    • 3. 参考阅读
  • 参考资料

面向对象设计的六大设计原则表

缩写 英文名称 中文名称
SRP Single Responsibility Principle 单一职责原则
OCP Open Close Principle 开闭原则
LSP Liskov Substitution Principle 里氏替换原则
LoD Law of Demeter ( Least Knowledge Principle) 迪米特法则(最少知道原则)
ISP Interface Segregation Principle 接口分离原则
DIP Dependency Inversion Principle 依赖倒置原则

一、 "开放-封闭"原则(OCP)

Open-Closed Principle原则讲的是:一个软件实体应当对扩展开放,对修改关闭。

优点:

通过扩展已有软件系统,可以提供新的行为,以满足对软件的新的需求,使变化中的软件有一定的适应性和灵活性。
已有软件模块,特别是最重要的抽象层模块不能再修改,这使变化中的软件系统有一定的稳定性和延续性。

例子:玉帝招安美猴王

当年大闹天宫便是美猴王对玉帝的新挑战。美猴王说:"'皇帝轮流做,明年到我家。'只教他搬出去,将天宫让于我!“对于这项挑战,太白金星给玉皇大帝提出的建议是:“降一道招安圣旨,宣上界来…,一则不劳师动众,二则收仙有道也。”
换而言之,不劳师动众、不破坏天规便是"闭”,收仙有道便是"开"。招安之道便是玉帝天庭的"开放-封闭"原则。

招安之法的关键便是不允许更改现有的天庭秩序,但允许将妖猴纳入现有秩序中,从而扩展了这一秩序。
用面向对象的语言来讲,不允许更改的是系统的抽象层,而允许更改的是系统的实现层。


二、 里氏代换原则(LSP)

Liskov Substitution Principle(里氏代换原则):子类型(subtype)必须能够替换它们的基类型。

[图] 白马、黑马

反过来的代换不成立

《墨子·小取》说:"娣,美人也,爱娣,非爱美人也……"娣便是妹妹,哥哥喜爱妹妹,是因为两人是兄妹关系,而不是因为妹妹是个美人。因此,喜爱妹妹不等同于喜爱美人。
用面向对象语言描述,美人是基类,妹妹是美人的子类。哥哥作为一个有"喜爱()"方法,接受妹妹作为参数。那么,这个"喜爱()"方法一般不能接受美人的实例。

一个违反LSP的简单例子(长方形和正方形)

1. Rectangle和Square类的定义


public class Rectangle
{private long width;private long height;public void setWidth(long width){this.width = width;}public long getWidth(){return this.width;}public void setHeight(long height){this.height = height;}public long getHeight(){return this.height;}
}public class Square
{private long side;public void setSide(long side){this.side = side;}public long getSide(){return side;}
}

2. Square和Rectangle的具体实现

using System;public class Rectangle
{private long width;private long height;public void setWidth(long width){this.width = width;}public long getWidth(){return this.width;}public void setHeight(long height){this.height = height;}public long getHeight(){return this.height;}
}public class Square : Rectangle
{private long side;public void setWidth(long width){setSide(width);}public long getWidth(){return getSide();}public void setHeight(long height){setSide(height);}public long getHeight(){return getSide();}public long getSide(){return side;}public void setSide(long side){this.side = side;}
}public class SmartTest
{public void resize(Rectangle r){while (r.getHeight() >= r.getWidth() ){r.setWidth(r.getWidth() + 1);}}
}

3. 错误示例的UML图

在执行SmartTest的resize方法时,如果传入的是长方形对象,当高度大于宽度时,会自动增加宽度直到超出高度。但是如果传入的是正方形对象,则会陷入死循环。

4. 代码重构

public interface Quadrangle
{public long getWidth();public long getHeight();
}public class Rectangle : Quadrangle
{private long width;private long height;public void setWidth(long width){this.width = width;}public long getWidth(){return this.width;}public void setHeight(long height){this.height = height;}public long getHeight(){return this.height;}
}public class Square : Quadrangle
{private long side;public void setSide(long side){this.side = side;}public long getSide(){return side;}public long getWidth(){return getSide();}public long getHeight(){return getSide();}
}

5. 重构后的UML图


三、 依赖倒置原则(DIP)

1. DIP的定义解读

  • 依赖倒置(Dependence Inversion Principle)原则讲的是:要依赖于抽象,不要依赖于具体。

  • 简单的说,依赖倒置原则要求客户端依赖于抽象耦合。

  • 原则表述:

    1. 抽象不应当依赖于细节
    2. 细节应当依赖于抽象
    3. 要针对接口编程,不针对实现编程

2. 举一个反面例子及解决办法

反面例子:

  • 缺点:耦合太紧密,Light发生变化将影响ToggleSwitch。

解决办法一:

将Light作成Abstract,然后具体类继承自Light。

  • 优点:ToggleSwitch依赖于抽象类Light,具有更高的稳定性,而BulbLight与TubeLight继承自Light,可以根据"开放-封闭"原则进行扩展。只要Light不发生变化,BulbLight与TubeLight的变化就不会波及ToggleSwitch。
  • 缺点:如果用ToggleSwitch控制一台电视就很困难了。总不能让TV继承自Light吧。

解决方法二:

  • 优点:更为通用、更为稳定。

结论:

  • 使用传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。
    依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。

四、 接口隔离原则(ISP)

1. 接口隔离原则的内容解读

接口隔离原则(Interface Segregation Principle)讲的是:使用多个专门的接口比使用单一的总接口总要好。
换而言之,从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小接口上的。
过于臃肿的接口是对接口的污染。不应该强迫客户依赖于它们不用的方法。

My object-oriented umbrella(摘自Design Patterns Explained)

Let me tell you about my great umbrella. It is large enough to get into! In fact, three or four other people can get in it with me. While we are in it, staying out of the rain, I can move it from one place to another. It has a stereo system to keep me entertained while I stay dry. Amazingly enough, it can also condition the air to make it warmer or colder. It is one cool umbrella.

My umbrella is convenient. It sits there waiting for me. It has wheels on it so that I do not have to carry it around. I don't even have to push it because it can propel itself. Sometimes, I will open the top of my umbrella to let in the sun. (Why I am using my umbrella when it is sunny outside is beyond me!)

In Seattle, there are hundreds of thousands of these umbrellas in all kinds of colors. Most people call them cars.

2. 实现方法

  1. 使用委托分离接口
  2. 使用多重继承分离接口

五、 合成/聚合复用原则(CARP)

1. 合成、聚合复用原则的解读

合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP)经常又叫做合成复用原则(Composite Reuse Principle或CRP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。
简而言之,要尽量使用合成/聚合,尽量不要使用继承。

  • Design to interfaces.
  • Favor composition over inheritance.
  • Find what varies and encapsulate it.
    (摘自:Design Patterns Explained)

2. 区分"Has-A"与"Is-A"

“Is-A"是严格的分类学意义上定义,意思是一个类是另一个类的"一种”。而"Has-A"则不同,它表示某一个角色具有某一项责任。


1. 错误示例

导致错误的使用继承而不是合成/聚合的一个常见的原因是错误的把"Has-A"当作"Is-A"。

例如

实际上,雇员、经理、学生描述的是一种角色,比如一个人是"经理"必然是"雇员",另外一个人可能是"学生雇员",在上面的设计中,一个人无法同时拥有多个角色,是"雇员"就不能再是"学生"了,这显然是不合理的。

错误源于把"角色"的等级结构与"人"的等级结构混淆起来,误把"Has-A"当作"Is-A"。


2. 解决办法


六、 迪米特法则(LoD)

1. 迪米特法则(LoD)的内容解读

迪米特法则(Law of Demeter或简写LoD)又叫最少知识原则(Least Knowledge Principle或简写为LKP),也就是说,一个对象应当对其它对象有尽可能少的了解。

其它表述:

  • 只与你直接的朋友们通信
  • 不要跟"陌生人"说话
  • 每一个软件单位对其它的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

2. 迪米特法则与设计模式

Facade模式
Mediator模式

3. 参考阅读

使民无知

  • 《老子》第三章曰:"是以圣人之治,虚其心,实其腹,弱其志,常使民无知无欲。"使被"统治"的对象"愚昧"化,处于"无知"的状态,可以使"统治"的成本降低。
  • 所谓"最少知识"原则,实际上便是老子的"使民无知"的统治之术。

不相往来

  • 《老子》云:“小国寡民……邻国相望,鸡犬之声相闻,民至老死,不相往来。”
  • 将被统治的对象隔离开来,使它们没有直接的通信,可以达到分化瓦解,继而分而治之的效果。
    迪米特法则与老子的"小国寡民"的统治之术不谋而合。

参考资料

阎宏,《Java与模式》,电子工业出版社

[美]James W. Cooper,《C#设计模式》,电子工业出版社

[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社

[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社

[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社
http://www.dofactory.com/Patterns/Patterns.aspx

[转] 设计模式的六大设计原则相关推荐

  1. IOS设计模式的六大设计原则之开放-关闭原则(OCP,Open-Close Principle)

    定义 一个软件实体(如类.模块.函数)应当对扩展开放,对修改关闭. 定义解读 在项目开发的时候,都不能指望需求是确定不变化的,大部分情况下,需求是变化的.那么如何应对需求变化的情况?这就是开放-关闭原 ...

  2. 设计模式之六大设计原则【入门】

    设计模式之六大设计原则 1 开闭原则 Open Closed Principle,OCP 1.1 概念 1.2 软件实体 1.3 开闭原则的作用 2. 单一职责原则 Single responsibi ...

  3. 设计模式的六大设计原则

    设计模式的六大设计原则 1. 开闭原则 1.1 开闭原则:Open Closed Principle,OCP 1.2 开闭原则的作用 2. 单一责任原则 2.1 单一职责原则:Single respo ...

  4. 设计模式之六大设计原则

    文章目录 一.六大设计原则(实际有七个) 1.单一职责 2.里氏替换原则 3.依赖倒置原则 4.接口隔离原则 5.迪米特法则(最少知道原则) 6.开闭原则 7.合成复用原则 二.总结 一.六大设计原则 ...

  5. 面向对象有哪几种常用的设计模式,六大设计原则是什么

    常用设计模式:单例模式(有的叫单元素模式,单态模式),工厂模式,观察者模式,命令链模式,策略模式. 1),OCP原则(也叫开闭原则) 2),SRP原则(职责单一原则) 3),OCP原则(里氏替换原则) ...

  6. 设计模式三大类及六大设计原则

    设计模式分为三大类: 创建型模式,共五种: 单例模式 工厂方法模式 抽象工厂模式 建造者模式 原型模式 结构型模式,共七种: 适配器模式 装饰模式 代理模式 外观模式 桥接模式 组合模式 享元模式 行 ...

  7. 引用防删——JAVA设计模式总结之六大设计原则

    JAVA设计模式总结之六大设计原则 从今年的七月份开始学习设计模式到9月底,设计模式全部学完了,在学习期间,总共过了两篇:第一篇看完设计模式后,感觉只是脑子里面有印象但无法言语.于是决定在看一篇,到9 ...

  8. JAVA六大设计原则 和 23种设计模式

    相关书籍:<大话设计模式>.<Java设计模式>.<设计模式之禅>.<研磨设计模式>.<Head First 设计模式> JAVA六大设计原 ...

  9. 设计模式必备知识点----六大设计原则

    六大设计原则 一,开闭原则 开闭原则的定义 什么是开闭原则 开闭原则的作用 开闭原则的优点 二,单一职责原则 单一职责定义 单一职责的作用 单一职责的优点 单一职责的违背原则 三,依赖倒置原则 依赖倒 ...

最新文章

  1. android 序列化_Android高级架构进阶之数据传输与序列化
  2. POJ 2385 Apple Catching
  3. 【阿里妈妈营销科学系列】第八篇:增强分析在营销分析场景下的实现和应用...
  4. Hazelcast入门
  5. B - 数据结构实验之栈与队列二:一般算术表达式转换成后缀式
  6. 程序员大部分时间都在“熟悉系统”
  7. eclipse Maven搭建SSH框架
  8. 苹果被拒的血泪史。。。(update 2015.11)
  9. 仿得微博字符限制效果
  10. MATLAB中定积分的求解
  11. Android NDK开发1——开发流程+依赖外部so+生成自实现so+静态注册JNI+动态注册JNI
  12. hydra 破解ssh 163邮箱
  13. 苹果海洋视频源直播源文件
  14. 元素定位163邮箱账号密码输入框问题,iframe嵌套
  15. WPF中UserControl 绑定样式(小白教程)
  16. 动物识别Python
  17. 解决ftp 出现Passive mode refused的办法
  18. drill apache_大数据SQL:Apache Drill查询执行功能概述–白板演练
  19. 齐二TK6916/20/26/32系列数控落地铣镗床简介6
  20. 谷歌优化有什么好处?外贸独立站如何提高谷歌优化排名?

热门文章

  1. Day11多态部分-6 【1.4 多态的应用以及注意事项】
  2. 运算符之:5、位运算符(7个)
  3. ai如何做倒角和圆角_石材路沿石是如何倒角的?倒角费用是多少?路沿石质量标准?...
  4. [Python人工智能] 二十一.Word2Vec+CNN中文文本分类详解及与机器学习(RF\DTC\SVM\KNN\NB\LR)分类对比
  5. HarmonyOS之应用工程结构与设备模板
  6. 《数据库原理与应用》(第三版) 第4章SQL Server 2012基础 习题参考答案
  7. 12.2 全局CSS样式
  8. BASIC-6 杨辉三角形
  9. 2015年第六届蓝桥杯C/C++ A组国赛 —— 第三题:显示二叉树
  10. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1078:求分数序列和