设计模式——六大设计原则

文章目录

  • 一、单一职责原则
  • 二、里式替换原则
  • 三、依赖倒置原则
  • 四、接口隔离原则
  • 五、迪米特法则
  • 六、开闭原则

一、单一职责原则

单一职责原则简称 SRP,他想表达的就是字面意思,一个类只承担一个职责。

有时候我们可以将一个复杂的接口拆成两个不同的接口,这两个接口承担着不同的责任,这就是依赖了单一职责原则;它的定义就是:应该有且仅有一个原因引起类的变更。

关于 职责 的定义很模糊,什么才是职责呢?不同的人有不同的解读,所以该原则很难运用,需要开发者的慧眼。


下面以大学学生工作管理程序为例介绍单一职责原则的应用。

二、里式替换原则

里式替换原则也叫 LSP 原则,没错就是你想的那个 lsp 😝。

其实是英文简写啦,LSP 即 Liskov Substitution Principle

继承是非常优秀的语言机制,它的优点如下:

  1. 代码共享:父类共享给子类;
  2. 提高代码的可扩展性:很多框架的接口都是通过继承父类实现的;

缺点是增加了代码的耦合性,降低了代码的灵活性。

但是从整体上看,继承还是利大于弊的,我们想要将利最大化,就需要用到 里式替换 了。


里氏替换原则通俗来讲就是:

  • 子类可以扩展父类的功能,但不能改变父类原有的功能
  • 只要父类出现的地方子类就可以出现,而且替换为子类不会出现任何错误。

三、依赖倒置原则

依赖倒置原则的 3 个含义:

  • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 抽象不应该依赖细节;
  • 细节应该依赖抽象;

这里的抽象指的就是 接口或抽象类 ,细节指的是 实现类

其核心思想是:要面向接口编程,不要面向实现编程

为什么面向接口呢?面向接口就是面向抽象,由于在软件设计中,细节具有多变性,而 抽象层相对稳定 ,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。


依赖倒置原则在 Java 中的表现是:

  • 模块之间的依赖通过抽象产生,实现类之间不能发生依赖关系,只能通过接口或抽象类产生;
  • 接口或抽象类不依赖于实现类;
  • 实现类依赖接口或抽象类;

我们以一个例子来看一下依赖倒置原则的重要性:

现在有一个司机,他想开一辆奔驰车。

代码可以这样写:

司机:

public class Driver() {public void drive(Benz benz) {benz.run();}}

奔驰车:

public class Benz() {public void run() {System.out.println("奔驰汽车开始运行...");}}

主函数:

public class Client() {public static void main() {Driver zhangSan = new Driver();Benz benz = new Benz();// 张三开奔驰车zhangSan.drive(benz);}}

这样运行起来,可以得到我们想要的结果,代码没有问题。

但是只有当需求变更的时候才能真正的检验代码的质量。

现在题目要求司机开宝马车,怎么改?

我们先创建出来宝马车:

public class BMW() {public void run() {System.out.println("宝马汽车开始运行...");}}

宝马车出来了,但是我们却没办法让张三将车开动起来,为什么?因为张三没有开动宝马车的方法啊。

此时我们发现我们的系统出现了问题:司机和奔驰车之间是紧耦合的关系,司机是实体类,奔驰车也是实体类,他们两个发生了依赖关系,违背了我们说的依赖倒置原则。

那怎么修改呢?

既然是面向接口,那我们就创建两个接口,让抽象的接口互相依赖:

下面介绍 3 种依赖的类型。

依赖的 3 种写法

依赖是可以传递的,A 对象依赖 B 对象,B 又依赖 C,C 又依赖 D······,但是只要我们做到抽象依赖,即使是多层的依赖传递也不怕。

对象的依赖关系有三种方式来传递,分别是:

1、构造函数传递依赖对象

public class Driver() {public void drive(Benz benz) {benz.run();}}

2、Setter 方法传递依赖对象

public interface IDriver {public void setCar(ICar car);public void drive();}

3、接口声明依赖对象

在接口的方法中声明依赖对象,也叫作接口注入。

public interface IDriver {public void driver(ICar car);}

那么我们在项目中怎么使用这个规则呢?可以从以下几个方面入手:

  1. 每个类尽量都要有接口或抽象类;
  2. 变量的表面类型尽量是接口或者抽象类;
  3. 任何类都不应该从具体类派生;
  4. 集合里式替换原则使用。

我们可以得出一个通俗的规则:

  • 接口负责定义 public 属性和方法,并且声明与其他对象的依赖关系;
  • 抽象类负责公共构造部分的实现;
  • 实现类准确的实现业务逻辑,同时对父类进行细化。

四、接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

就是要让接口中的方法尽可能的少而精。

同时注意,根据接口隔离原则拆分接口时,首先必须满足 单一职责原则 ,不能无限拆分。

例题:学生成绩管理程序。

分析:学生成绩管理程序一般包含插入成绩、删除成绩、修改成绩、计算总分、计算均分、打印成绩信息、査询成绩信息等功能,如果将这些功能全部放到一个接口中显然不太合理,正确的做法是将它们分别放在输入模块、统计模块和打印模块等 3 个模块中,其类图如图所示。

五、迪米特法则

迪米特法则(Law of Demeter,LoD)又叫作最少知识原则(Least Knowledge Principle,LKP)。

一个类应该对自己需要耦合或调用的类知道的最少,你的内部是如何复杂都和我没有关系,那是你的事情,我就知道你提供那么多 public 方法,我就调用这么多,其他的我一概不关心。

先说一下什么是 朋友类

  • 出现在成员变量、方法的输入输出参数中的类称为成员朋友类;
  • 出现在方法体内部的类不属于朋友类。

迪米特法则的目的就是低耦合,它包含 4 层含义:

1、只和朋友交流

也就是说符合迪米特法则的类中的方法,应该不能出现非朋友类,不能和陌生人有交流。

2、朋友之间也是有距离的

人与人之间是有距离的,类与类之间也有距离,不能太过亲密。

比如 A 类有 3 个方法,被 B 类的一个方法 m1 全部调用了,这样一来就会有一个问题,当 A 类修改方法的名称时,B 类也要修改 m1 方法,这就是耦合太紧了。

解决办法就是将 m1 方法转移到 A 类中去,让 B 类调用 A 的 m1 方法,这样就是高内聚低耦合了。

同时 A 类中的 3 个方法可以设置成私有的,因为只有他自己调用,只需要将 m1 设置成 public 就可以了。

一个类公开的 public 属性或方法越多,修改时涉及的面也就越大,迪米特法则要求类 羞涩 一点,尽量内敛。

3、是自己的就是自己的

如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

4、谨慎使用 Serializable


明星与经纪人的关系实例。

分析:明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则,其类图如图所示。

六、开闭原则

开闭原则是 Java 世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。

他要求软件实体应该对扩展开放,对修改关闭。

这里的软件实体包括:

  • 模块;
  • 抽象和类;
  • 方法。

前面提到的几个原则都是开闭原则的具体形态,也就是说前五个原则就是指导设计的工具和方法,而开闭原则才是精神领袖。

开闭原则 在面向对象设计领域中的地位类似于牛顿第一定律在力学中的地位。


下面以 Windows 的桌面主题为例介绍开闭原则的应用。

例题:Windows 的桌面主题设计。

分析:Windows 的主题是桌面背景图片、窗口颜色和声音等元素的组合。用户可以根据自己的喜爱更换自己的桌面主题,也可以从网上下载新的主题。这些主题有共同的特点,可以为其定义一个抽象类(Abstract Subject),而每个具体的主题(Specific Subject)是其子类。用户窗体可以根据需要选择或者增加新的主题,而不需要修改原代码,所以它是满足开闭原则的,其类图如图所示。

软件设计最大的难题就是应对需求的变化,但是繁杂的需求变化又是不可预料的。我们要为不可预料的事情做好准备,大师们为我们提供了 6 大设计原则和 23 种设计模式来 封装 未来的变化。来源:https://www.icode9.com/content-4-793951.html

(0)

相关推荐

  • 二十三种设计模式修炼手册

    不知不觉,在开发这条道路上摸爬打滚也有些年头了,偶尔回头看看以前写的代码,真可谓粗糙至极.当然了,那时候还是小白,代码写得难看些情有可原,不过现在可不能再用以前的标准去衡量自己了,因此掌握一些高级架构 ...

  • 掌握设计原则,你就是光(25个问题,你会几个)

    25个问题,你会几个 如何理解单一职责原则? 如何判断职责是否足够单一? 职责是否设计得越单一越好? 什么是开闭原则? 修改代码就一定意味着违反开闭原则吗? 怎样的代码改动才被定义为扩展或者说是修改? ...

  • 设计模式-七大软件设计原则

    设计模式 参考资料 图解设计模式 大话设计模式 设计模式之禅 github我见过最好的设计模式 http://c.biancheng.net/view/1326.html 基本原则 开闭原则 在设计的 ...

  • 设计模式6大原则详解

    设计模式六大原则: 面向对象语言开发过程中,推荐的一些指导性原则(并不是强制要求的) 1. 单一职责原则(Single Responsibility Principle) 2. 里氏替换原则(Lisk ...

  • 面向对象六大原则

    这篇文章主要讲的是面向对象设计中,应该遵循的六大原则.只有掌握了这些原则,才能更好的理解设计模式. 我们接下来要介绍以下6个内容. 单一职责原则--SRP 开闭原则--OCP 里氏替换原则--LSP ...

  • 设计模式-6大设计原则

    单一职责原则(SRP:Single Responsibility Principle) 定义:应该有且仅有一个原因引起类的变更. 优点: 类的复杂性降低: 可读性提高: 可维护性提高: 变更引起的风险 ...

  • "设计模式我学过呀,就是没用过"

    回复"000"获取大量电子书 写在前面 在开发中,不使用设计模式也不是不可以,但是用好设计模式能帮忙我们更好的去解决实际问题. 其实,我们天天都在和设计模式打交道,很多人却完全不知 ...

  • 面向对象设计原则(SOLID原则)

    一.单一功能(single responsibility) 单一功能原则,也叫单一职责原则.简单来说,就是一个类应该只有一个引起它变化的原因,其中心思想就是面向对象设计原则中的高内聚,低耦合.当分析有 ...

  • 【工程基础】校招研发工程师笔试题

    【工程基础】校招研发工程师笔试题

  • 【资料】23种设计模式和六大设计原则

    程序IT圈 www.cxyquan.com 优秀的程序猿技术公众号 1 设计模式的六大原则 ☛开闭原则 对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果.简 ...

  • 【设计模式】设计原则--面向接口编程你理解的对吗?

    最近看了<Head First Design Patterns>这本书.正如其名,这本书讲的是设计模式(Design Patterns),而这本书的第一章,讲的是很重要的一些设计原则(De ...

  • Java设计模式-软件设计原则

    在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据6条原则来开发程序,从而提高软件开发效率.节约软件开发成本和维护成本. 1 开闭原则 对扩展开放,对修改 ...

  • 设计模式 - 七大设计原则(四)- 合成复用原则与设计原则总结

    概述 简单介绍一下七大设计原则: 开闭原则:是所有面向对象设计的核心,对扩展开放,对修改关闭 依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体 单一职责原则:一个接口只负责一件事情,只能有一个原因 ...

  • 设计模式 - 七大设计原则(三)- 迪米特法则与里氏替换原则

    概述 简单介绍一下七大设计原则: 开闭原则:是所有面向对象设计的核心,对扩展开放,对修改关闭 依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体 单一职责原则:一个接口只负责一件事情,只能有一个原因 ...

  • 六大设计原则(二)LSP里氏替换原则

    里氏替换原则LSP(Liskov Subsituation Principle) 里氏替换原则定义 所有父类出现的地方可以使用子类替换并不会出现错误或异常,但是反之子类出现的地方不一定能用父类替换. ...

  • 六大设计原则(一)SRP单一职责原则

    单一职责原则SRP(Single reponsibility principle) BO(Business Object):业务对象 Biz(Business Logic):业务逻辑 SRP最简单的例 ...

  • Python设计原则有哪些?六大类!

    Python是一种跨平台的计算机程序设计语言. 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言,现在各大领域都有Python的身影,Python可以说是无处不在了.但是很多人对Pyth ...