设计模式学习笔记——概述

什么是设计模式

软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。

设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。

设计模式分类

设计模式一般有两种分类方式,分别为:

  1. 按目的分:创建型模式、结构型模式和行为型模式
  2. 按作用范围分:类模式和对象模式
设计模式分类表

以上分类现在先看个眼熟,后续当所有设计模式学完后再回头看它会觉得豁然开朗滴~当然如果现在想去看一看分类的细节讲解,可以戳这个连接

七条原则

在正式学习23种设计模式之前,首先应了解软件开发的七条原则。为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据这7条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。

1.开闭原则

软件实体应当对扩展开放对修改关闭

简单说就是在开发时将可能发生变化的因素不要“写死”,而是抽象出来,在后续通过扩展模块的功能,使其满足新的需求。
实现开闭原则可以通过“抽象约束封装变化”的方法,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
【eg】:Windows 的桌面主题设计
如下图,访问类在编写代码时需要显示主题,这时我们只需要依赖AbstractSubject接口/类(抽象约束),每新增一个主题(封装变化)则去实现/继承它(对扩展开放)。这样就无需在更改主题时改变访问类的代码(对修改关闭)。

开闭原则示例

2.里氏替换原则

继承必须确保超类所拥有的性质在子类中仍然成立

里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。该原则表示:子类可以扩展父类的功能,但不能改变父类原有的功能。即子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法
【eg.】:“几维鸟不是鸟”
如下图,几维鸟、鸵鸟等不会飞的鸟是没有飞行速度的,与其继承鸟类后重写setFlySpeed方法或者getFlyTime方法,里氏替换原则更倾向于直接继承自更适合的类(尽量不要重写父类的方法),例如这里的动物类。

里氏替换原则示例

3.依赖倒置原则

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

核心思想就是要面向接口编程,不要面向实现编程。
实际编程中遵循以下四点即可满足依赖倒置原则:

  • 每个类尽量提供接口或抽象类,或者两者都具备。
  • 变量的声明类型尽量是接口或者是抽象类。
  • 任何类都不应该从具体类派生。
  • 使用继承时尽量遵循里氏替换原则。

【eg.】:“顾客购物程序”
如下图,你会发现这个类图与开闭原则中的例子非常相似,实际上,依赖倒置原则就是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。


依赖倒置原则示例

4.单一职责原则

单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分

单一职责原则的核心就是控制类的粒度大小将对象解耦、提高其内聚性
单一职责原则是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,再封装到不同的类或模块中。而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。
【eg.】:大学学生工作管理程序
如下图,你在区分职责时自然可以直接用一个老师类完成所有工作,但是这样便违背了单一职责原则(尽量控制类的力度大小),故将其分为辅导员和学业导师分别完成生活辅导与学业辅导两方面的内容(对象解耦,提高内聚性)。

单一职责原则示例

5.接口隔离原则

客户端不应该被迫依赖于它不使用的方法
一个类对另一个类的依赖应该建立在最小的接口上

以上两个定义的含义是:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
划分接口时,一个接口尽可能只服务于一个子模块或业务逻辑。
接口隔离原则和单一职责原则在描述时很相像,但两个有着明显的区别,与其这里用文字描述一些难以理解的概念,不如自己看实例去体会,多对比下面“学生成绩管理”实例与上面“大学学生工作管理”实例。你品,你细品……
【eg.】:学生成绩管理程序
学生成绩管理程序一般包含插入成绩、删除成绩、修改成绩、计算总分、计算均分、打印成绩信息、査询成绩信息等功能,如果将这些功能全部放到一个接口中显然不太合理,正确的做法是将它们分别放在输入模块、统计模块和打印模块等 3 个模块中


接口隔离原则示例

6.迪米特法则(最少知识原则)

只与你的直接朋友交谈,不跟“陌生人”说话

如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
从迪米特法则的定义和特点可知,它强调以下两点:

  • 从依赖者的角度来说,只依赖应该依赖的对象。
  • 从被依赖者的角度说,只暴露应该暴露的方法。

【eg.】:明星和经纪人
从职责来看,明星本身该做的事情是提升自身能力,练习唱歌跳舞或演戏等。而联系经纪公司,接戏,联系粉丝(陌生人)等则是经纪人(朋友)要干的事情。明星只需要与经纪人交谈,无需直接与粉丝等联系。

迪米特法则示例

7.合成复用原则

在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。
之所以提倡优先使用合成关系而不是继承关系是为了更好的维持类的封装性、降低类与类之间的耦合性、提高复用灵活性。
合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。
【eg.】:汽车分类管理程序
对比以下使用继承方法与使用合成方法的区别。用继承关系实现会产生很多子类,而且增加新的“动力源”或者增加新的“颜色”都要修改源代码,这违背了开闭原则,显然不可取。但如果改用组合关系实现就能很好地解决以上问题。


非合成复用示例
合成复用示例

8.7种设计原则总结

这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

参考

http://c.biancheng.net/view/1317.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容