软件工程课程 https://gitee.com/mengning997/se中介绍了设计原理与设计模式,本博客聚焦于设计模式,参考此课程调研整理了设计模式并分析了适用场景。

设计原理 design principle

1、单一职责原则(Single Responsibility Principle SRP)

不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,否则就应该把类拆分。

2、开闭原则 (Open-Closed Principle OCP)

对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。

3、里氏替换原则(Liskov Substitution Principle LSP)

任何基类可以出现的地方,子类一定可以出现。

4、接口隔离原则(Interface Segregation Principle ISP)

每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的

5、依赖倒置原则(Dependence Inversion Principle DIP)

面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

6、迪米特法则(最少知道原则)(Law of Demeter)

一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

设计模式 design pattern

Creational patterns 创建型模式

这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复用性。

1. Factory Method 工厂方法模式

生产单一产品,复用现有对象

工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。生产单一产品

  • 适用场景:无法预知对象确切类别及其依赖关系时;希望用户能扩展你软件库或框架的内部组件;希望复用现有对象来节省系统资源, 而不是每次都重新创建对象

原则

✔️单一职责原则。 你 可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。

✔️开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。( 简单工厂模式违背开闭原则

2. Abstract Factory 抽象工厂模式

生产一个产品体系,不基于具体类构建

抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。 生产一个产品体系

适用场景:如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。

原则

✔️单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。

✔️开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。

3. Builder建造者模式(生成器模式)

将对象构造代码抽取出来放到生成器中,创建不同形式的产品

生成器模式是一种创建型设计模式, 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。生成器模式建议将对象构造代码从产品类中抽取出来, 并将其放在一个名为生成器的独立对象中。

适用场景:使用生成器模式可避免 “重叠构造函数 (telescopic constructor)” 的出现;使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用生成器模式;造组合树或其他复杂对象

原则

✔️单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。

4. Prototype 原型模式(克隆)

复制已有对象而不需要知道任何创建细节,使复制代码独立于被复制对象所属的具体类

原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。优点:建立相应数目的原型并克隆它们通常比每次用合适的状态手工实例化该类更方便一些

适用场景:如果你需要复制一些对象, 同时又希望代码独立于这些对象所属的具体类, 可以使用原型模式;如果子类的区别仅在于其对象的初始化方式, 那么你可以使用该模式来减少子类的数量。 别人创建这些子类的目的可能是为了创建特定类型的对象。

5. Singleton单例模式

一个类只有一个实例,提供一个访问该实例的全局结点,适用某个类对所有客户端都只有一个可用的实例

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。单例(Singleton)类声明了一个名为getInstance获取实例的静态方法来返回其所属类的一个相同实例。

适用场景:如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式;需要更加严格地控制全局变量

原则

❌ 单一职责原则。该模式同时解决了两个问题。1.保证一个类只有一个实例 2.该实例提供一个全局访问节点

Structural patterns 结构型模式

这类模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。

1. Adapter 适配器模式 (封装器模式)

使接口不兼容的对象可以合作,将缺少的对象封装在适配器中

适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作 *。适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 *

适用场景:当你希望使用某个类, 但是其接口与其他代码不兼容时, 可以使用适配器类;如果您需要复用这样一些类, 他们处于同一个继承体系, 并且他们又有了额外的一些共同的方法, 但是这些共同的方法不是所有在这一继承体系中的子类所具有的共性,可以将缺少功能的对象封装在适配器中, 从而动态地获取所需功能。

原则

✔️单一职责原则。 你可以将接口或数据转换代码从程序主要业务逻辑中分离。

✔️开闭原则。只要客户端代码通过客户端接口与适配器进行交互, 你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器。

2. Bridge 桥接模式

将类拆分为抽象和实现

桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用。桥接模式通过将继承改为组合的方式来解决这个问题。 具体来说, 就是抽取其中一个维度并使之成为独立的类层次, 这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。

抽象部分 : 程序的 GUI 层。

实现部分 : 操作系统的 API。

适用场景: 如果你想要拆分或重组一个具有多重功能的庞杂类 \ (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式;如果你希望在几个独立维度上扩展一个类, 可使用该模式;如果你需要在运行时切换不同实现方法, 可使用桥接模式。

原则

✔️单一职责原则。 你可以新增抽象部分和实现部分, 且它们之间不会相互影响。

✔️开闭原则。抽象部分专注于处理高层逻辑, 实现部分处理平台细节。

3. Composite 组合模式 (Object Tree 对象树)

使用独立对象一般使用组合对象

组合模式是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们。

适用场景:需要实现树状对象结构;希望客户端代码忽略组合对象与单个对象的不同以相同方式处理简单和复杂元素。

原则

✔️开闭原则。无需更改现有代码, 你就可以在应用中添加新元素, 使其成为对象树的一部分。

4. Decorator 装饰者模式 (Wrapper)

为原对象绑定新的行为

装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为

适用场景:在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为;用继承来扩展对象行为的方案难以实现或者根本不可行

原则

✔️单一职责原则。你可以将实现了许多不同行为的一个大类拆分为多个较小的类。

5. Facade 外观模式

为复杂类提供简单接口,包含客户端真正关心的功能

外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口 。外观类为包含许多活动部件的复杂子系统提供一个简单的接口。 与直接调用子系统相比, 外观提供的功能可能比较有限, 但它却包含了客户端真正关心的功能。

适用场景:需要一个指向复杂子系统的直接接口, 且该接口的功能有限;需要将子系统组织为多层结构,外观来定义子系统中各层次的入口,你可以要求子系统仅使用外观来进行交互, 以减少子系统之间的耦合。

6. Flyweight 享元模式 (Cache 缓存)

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

适用场景:支持大量对象且没有足够的内存容量

原则:

❌ 开闭原则

7. Proxy 代理模式

代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。代理模式建议新建一个与原服务对象接口相同的代理类 , 然后更新应用以将代理对象传递给所有原始对象客户端。

适用场景:

延迟初始化 (虚拟代理)。 如果你有一个偶尔使用的重量级服务对象 , 一直保持该对象运行会消耗系统资源时, 可使用代理模式。

访问控制 (保护代理)。 如果你只希望特定客户端使用服务对象, 这里的对象可以是操作系统中非常重要的部分, 而客户端则是各种已启动的程序 (包括恶意程序), 此时可使用代理模式。

本地执行远程服务 ( 远程代理 )。适用于服务对象位于远程服务器上的情形。

记录日志请求 (日志记录代理)。适用于当你需要保存对于服务对象的请求历史记录时。 代理可以在向服务传递请求前进行记录。

智能引用。 可在没有客户端使用某个重量级对象时立即销毁该对象。

原则

✔️ 开闭原则。你可以在不对服务或客户端做出修改的情况下创建新代理。

Behavioral patterns 行为模式

这类模式负责对象间的高效沟通和职责委派。

1. Chain of Responsibility 责任链模式

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送 。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。(先判断是否能handle)

适用场景:当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知 ;必须按顺序执行多个处理者;所需处理者及其顺序必须在运行时进行改变。( 如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。)

原则

✔️单一职责原则。你可对发起操作和执行操作的类进行解耦。

✔️开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。

2. Command 命令模式

仅包含触发请求

命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象 。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。命令模式建议 GUI 对象不直接提交这些请求。 你应该将请求的所有细节 (例如调用的对象、 方法名称和参数列表) 抽取出来组成命令类, 该类中仅包含一个用于触发请求的方法

适用场景:通过操作来参数化对象;想要将操作放入队列中、 操作的执行或者远程执行操作;实现操作回滚功能

原则

✔️单一职责原则。你可以解耦触发和执行操作的类。

✔️开闭原则。你可以在不修改已有客户端代码的情况下在程序中创建新的命令。

3. Iterator 迭代器模式

遍历

迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。迭代器模式的主要思想是将集合的遍历行为抽取为单独的迭代器对象。

适用场景:当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑);可以减少程序中重复的遍历代码;希望代码能够遍历不同的甚至是无法预知的数据结构。

原则

✔️单一职责原则。通过将体积庞大的遍历算法代码抽取为独立的类, 你可对客户端代码和集合进行整理。

✔️开闭原则。你可实现新型的集合和迭代器并将其传递给现有代码, 无需修改现有代码。

4. Mediator 中介者模式

中介者模式是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。中介者模式建议你停止组件之间的直接交流并使其相互独立。 这些组件必须调用特殊的中介者对象, 通过中介者对象重定向调用行为, 以间接的方式进行合作。 最终, 组件仅依赖于一个中介者类, 无需与多个其他组件相耦合。

适用场景:当一些对象和其他对象紧密耦合以致难以对其进行修改时;当组件因过于依赖其他组件而无法在不同应用中复用时;为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时。

原则

✔️单一职责原则。你可以将多个组件间的交流抽取到同一位置, 使其更易于理解和维护。

✔️开闭原则。你无需修改实际组件就能增加新的中介者。

5. Memento 备忘录模式

保存和回复状态

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态

适用场景:需要创建对象状态快照来恢复其之前的状态时;当直接访问对象的成员变量、 获取器或设置器将导致封装被突破时。

6. Observer 观察者模式

订阅机制

观察者模式是一种行为设计模式, 允许你定义一种订阅机制 , 可在对象事件发生时通知多个 “观察” 该对象的其他对象。拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher) 。 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)

适用场景:当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时;当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。

原则

✔️开闭原则。你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。

7. State 状态模式

状态变化时改变其行为

状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。状态模式与有限状态机的概念紧密相关

  • 适用场景:对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更;某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时;当相似状态和基于条件的状态机转换中存在许多重复代码时。

原则

✔️单一职责原则。将与特定状态相关的代码放在单独的类中。

✔️开闭原则。无需修改已有状态类和上下文就能引入新状态。

8. Strategy 策略模式

策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。策略模式建议找出负责用许多不同方式完成特定任务的类, 然后将其中的算法抽取到一组被称为策略的独立类中。

适用场景:想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时;有许多仅在执行某些行为时略有不同的相似类;算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来;当类中使用了复杂条件运算符以在同一算法的不同变体中切换时

原则

✔️开闭原则。你无需对上下文进行修改就能够引入新的策略。

9. Template Method 模板方法模式

模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。

适用场景:只希望客户端扩展某个特定算法步骤, 而不是整个算法或其结构时;当多个类的算法除一些细微不同之外几乎完全一样时。

原则

❌ 里氏替换原则。 通过子类抑制默认步骤实现可能会导致违反里氏替换原则 。

10. Visitor 访问者模式

访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。访问者模式建议将新行为放入一个名为访问者的独立类中, 而不是试图将其整合到已有类中。 现在, 需要执行操作的原始对象将作为参数被传递给访问者中的方法, 让方法能访问对象所包含的一切必要数据。最终还是修改了节点类, 但毕竟改动很小。具体元素 (Concrete Element) 必须实现接收方法。

适用场景:需要对一个复杂对象结构 (例如对象树) 中的所有元素执行某些操作;可使用访问者模式来清理辅助行为的业务逻辑;当某个行为仅在类层次结构中的一些类中有意义, 而在其他类中没有意义时。

原则

✔️单一职责原则。你可以引入在不同类对象上执行的新行为, 且无需对这些类做出修改。

✔️开闭原则。可将同一行为的不同版本移到同一个类中。

❌ 违反了依赖倒置原则,为了达到“区别对待”而依赖了具体类,没有依赖抽象

❌ 具体元素对访问者公布细节,违反了迪米特原则

参考资料 : 代码中的软件工程 https://gitee.com/mengning997/se

软件工程中的设计原理与设计模式相关推荐

  1. 软件工程(总体设计②设计原理)

    设计原理 模块化 模块是由边界元素限定的相邻程序元素的序列,而且有一个总体标识符代表它. 按照模块的定义,过程.函数.子程序和宏,都可作为模块. 面向对象方法学中的对象是模块,对象内的方法也是模块.模 ...

  2. 电子小帮手电路中的设计原理

    01电子小帮手   很多电子爱好者,初学者在碰到一个半导体器件的时候,需要确认它的型号.功能以及管脚定义,才能够正确使用它.但当你从一块印刷电路板上拆下一个器件,或者从元器件盒中拿出一个器件,除非能够 ...

  3. 软件工程中过程设计的工具

    描述程序处理过程的工具称为过程设计工具,它们可以分为图形.表格.和语言3类. 不论是哪类工具,对它们的基本要求都是能提供对设计的无歧义的描述. 即:应该能指明控制流程.处理功能.数据组织,以及其他方面 ...

  4. 浅析软件工程中的一些常见设计原则

    老子说:有道无术,术尚可求也.有术无道,止于术.如果说设计模式是"术",那么设计原则就是"道".今天,我们一起来聊聊软件工程中一些常用的设计原则. DRY 原则 ...

  5. 移动端界面中的版式设计原理

    "我总觉得页面不太好看但是我又说不出来","我不懂设计,但是我就是觉得不协调","你觉得这好看?你的审美要加强啊"这些听着熟悉的话往往是产品 ...

  6. koa2异常处理_koa2 中的错误处理以及中间件设计原理

    其实这不是一个问题,因为就 koa2 而言,他已经帮我做好了统一错误处理入口 app.onerror 方法. 我们只要覆盖这个方法,就可以统一处理包括 中间件,事件,流 等出现的错误. 但我们始终会看 ...

  7. java中的saturn_Saturn分布式调度平台系列:高屋建瓴之设计原理简析

    由于业务系统中使用了Saturn作为分布式调度平台并且计划对其作二次开发,因此看了官方文档及源码,简单做了梳理与总结.Saturn是唯品会开源的一款定时任务调度平台,相对于传统的Spring Batc ...

  8. 电源设计中电容的工作原理及选用

    电源往往是我们在 电路设计过程中最容易忽略的环节.作为一款优秀的设计,电源设计应当是很重要的,它很大程度影响了整个系统的性能和成本. 电源设计中的 电容使用,往往又是电源设计中最容易被忽略的地方. 一 ...

  9. 移动端界面中的版式设计原理(上)

    "我总觉得页面不太好看但是我又说不出来","我不懂设计,但是我就是觉得不协调","你觉得这好看?你的审美要加强啊"这些听着熟悉的话往往是产品 ...

最新文章

  1. 已知2个整形数据a,b.不使用if,?:以及其他任何条件判断的语法,找出a跟b中数据的大者。
  2. Windows下安装Cygwin配置Hadoop集群
  3. topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
  4. 计算机精英协会考核题 —— 第二题:蛇形填数
  5. JavaScript If…Else 语句
  6. python根据数据生成图像_从三个numpy数组生成图像数据
  7. 前端学习(3252):react脚手架
  8. 嵌入式Linux入门7:kernel移植
  9. python伪造邮件发件地址_Python:向多个地址发送电子邮件
  10. 【安装配置】克隆方式安装Oracle数据库软件
  11. mysql表误删回复_mysql数据库数据删除怎么恢复
  12. 如何在集合中巧用Where来查找相关元素
  13. Base64压缩UUID长度替换Hibernate原有UUID生成器
  14. ls在系统中常用的选项与用法
  15. 面向创新设计的汽车外形曲面三维逆向建模
  16. python用keras库做个股票分析小程序
  17. 不想在网易博客写技术文章了
  18. 小米电视android版本最好,小米电视安装当贝桌面+安卓TV最简单好用的NAS播放器...
  19. 3D游戏与编程——UI系统
  20. 好用的Google浏览器插件

热门文章

  1. 听我说说我的博客: 月访问量过万的个人IT博客的技术史 1
  2. linux 移动剪切命令,Linux切换/增加/查看/寻找/移动/拷贝/删除目录命令实例讲解...
  3. 华为升级harmonyos的机型名单,华为新机将预置HarmonyOS 2.0,分离前的荣耀老机型也不例外...
  4. 华为新机鸿蒙,华为鸿蒙新机来袭:几乎100%全面屏+麒麟980+4500mAh 这才是华为
  5. 应用于图像识别的深度残差网络:ResNet
  6. Hystrix断路器(熔断器)
  7. c语言int四个字节取值范围,int的取值范围怎么算
  8. java画熊猫_Java-基础练习2
  9. 解决windows本地磁盘图标不显示、异常
  10. 【持续更新】多媒体文件格式