从问题到解决方案:理解设计模式
软件开发中一个有趣的事实是,你几乎总是不是第一个遇到特定问题的人。这个问题可能自软件开发诞生之初就一直存在。在这篇博文中,我们将探讨设计模式、我们为什么需要它们,并对一些设计模式进行概述。
设计模式是一种系统性的方法,用于解决程序员经常遇到的问题。它描述了解决这些问题的通用标准。无论问题的具体领域是什么,它提供的解决方案都可以重复使用。因此,下次你遇到编程问题时,请注意,你不必从头开始重新寻找解决方案。
为什么要使用设计模式?
- 经验使人完美:作为开发人员,您必须首先了解现有的优秀设计、它们的应用领域和权衡,以便您可以重复使用它们或开发自己的设计。
- 共享设计语言:设计模式为程序员提供了通用的词汇表。这有助于有效地相互沟通,减少误解,提高生产力。
- 更好的可扩展性:设计模式有助于使系统更具可扩展性,使其能够随着需求的变化而增长和适应。
- 改进的代码结构:设计模式有助于以一致且有组织的方式构建代码,使其更易于理解和维护。这可以提高代码质量并缩短开发时间。
设计模式的元素
- 名称- 是用来描述设计问题的句柄。它很有必要,因为它为程序员提供了共同的理解基础。
- 问题——用于描述何时可以使用该模式。
- 解决方案- 是一个描述元素及其关系但不提供实施细节的模板。
- 后果- 用于描述模式的权衡。例如:时间和空间的权衡、灵活性、可扩展性等等。
设计模式的类型
《设计模式:可复用面向对象软件的要素》(俗称“四人帮”)是软件工程的基石,它将设计模式带入了主流。本书细分了 23 种不同的设计模式,分为以下 3 类:
- 创造型——他们关注对象创建技术。
- 结构性——它们关注以灵活有效的方式组合对象和类。
- 行为- 它们关注类和对象之间的交互及其责任。
六种设计模式简介
以下部分将概述 6 种软件设计模式(每个类别 2 种)以及如何使用它们来解决常见的编程挑战。
1. 单例
单例模式是一种创建模式,它确保创建一个类的单个实例并提供对该实例的全局访问点。
原因:
假设您正在构建数据库连接类:
- 您肯定不想为每个需要访问的对象都创建一个单独的数据库实例。这样做成本很高。这个概念也适用于其他共享资源,例如文件。
- 您希望提供对该实例的全局且便捷的访问。与全局变量类似,单例模式允许您从程序中的任何位置访问对象。
如何:
实现单例模式的方法有很多种。然而,所有实现都遵循以下基本概念:
- 与每次调用都会创建新对象的常规构造函数不同,Singleton 类具有私有构造函数。私有构造函数可防止其他对象实例化 Singleton 类的对象。
- 私有实例变量。
- 返回该实例引用的静态方法。此静态方法本质上充当构造函数,并在底层调用私有构造函数来创建对象(首次请求时)或返回缓存的对象(用于后续请求)。
2.工厂方法
工厂方法也是另一种创建型模式,它提供了创建对象的接口,但由子类决定实例化哪个类。换句话说,子类可以更改要创建对象的类型。
原因:
假设您正在使用工厂方法设计模式创建一个日志框架,用于记录不同类型的消息,包括但不限于错误消息、警告消息和参考消息。在此用例中:
- 记录器可以提供用于创建不同类型消息的工厂方法。
- 使用此记录器的客户端代码不需要知道消息的具体实现,它只需要知道创建消息的接口。
- 您可以提供灵活性。如果对象创建过程发生变化(例如,添加了一个新类),则只需更新工厂方法。无需更改使用这些对象的客户端代码。
如何:
- 用对特定工厂方法的调用替换直接对象构造调用。
- 通过调用工厂方法来创建对象,而不是调用构造函数。
3. 适配器
适配器是一种结构设计模式,允许接口不兼容的对象协同工作。它位于客户端和客户端想要通信的接口之间的中间位置。
原因:
假设您正在按照适配器设计模式构建视频格式转换工具:
- 您的软件需要适配不同的视频格式,例如 MP4、AVI 和 FLV。它应该能够接收任何格式的视频并将其转换为所需的格式。目标和客户端之间的通信通过适配器进行。
- 如果将来您想要支持新格式,该模式会使它变得更容易,因为视频格式转换与特定的视频格式分离。
如何:
- 定义一个适配器类,将一个类(适配者)的不兼容接口转换为客户端期望的另一个接口(目标)。
- 使用此适配器与没有所需接口的其他类一起工作(重用)。
4. 装饰器
装饰器是另一种结构化设计模式,它允许你将新的行为附加到对象上,而不会影响同一类中其他对象的行为。虽然继承可以用来静态地改变对象的行为,但装饰器也可以用来动态地改变它。
原因:
假设您正在构建一个文本编辑器:
- 文本编辑器可以作为您的具体组件,而拼写检查器可以作为您的装饰器。
- 拼写检查器类应该具有与文本编辑器类相同的接口,以便可以用作装饰器。
- 拼写检查器类可以包装文本编辑器并为其添加拼写检查功能。这使得将来可以灵活地向编辑器添加新功能。
如何:
- 为组件和装饰器定义一个接口。
- 实现符合接口的具体组件和具体装饰器。
- 装饰器应该引用它们所装饰的组件,并委托组件执行基本行为。装饰器应该包含添加新行为的方法。
- 使用装饰器按所需顺序包装组件以附加附加行为。
注意:适配器为其主体提供了不同的接口。装饰器提供了增强的接口。
5.观察者
观察者是一种行为设计模式,它定义了对象之间的一对多依赖关系,以便当一个对象(称为主体)改变其状态时,其所有依赖者(称为观察者)都会自动收到通知并更新。
原因
假设您正在建立一个股票市场网站:
- 您可以使用观察者模式向用户更新最新的股票价格。
- 网站是主体,用户是观察者,每当股票价格发生变化时,网站都会通知用户。
如何
- 定义一个 Subject 对象。
- 定义观察者对象。观察者可以订阅或取消订阅事件流。
- 主体和观察者之间的关系不应该紧密耦合。
- 当主体的状态发生变化时,所有注册的观察者都会收到通知并进行更新。
6.策略
策略是另一种行为设计模式,它允许你定义一系列算法,封装每个算法,并使它们可以互换。它允许客户端在运行时选择算法的行为。
原因
假设您正在创建具有排序功能的软件:
- 可以在运行时选择排序算法(例如快速排序、插入排序或冒泡排序)并用于对项目集合进行排序。
- 排序策略可以轻松替换或修改,从而可以根据需要添加或删除功能
如何
- 创建一个定义常见行为的策略接口。
- 创建符合 Strategy 接口的具体策略类。每个具体策略都是算法的一个变体。
- 创建一个上下文类,定义对排序策略对象的引用。
- 上下文类应该有一个接受策略对象并调用所选策略的方法。
结论
总之,牢固掌握设计模式至关重要,特别是当你在软件工程领域取得进步时。
参考
https://www.amazon.com/gp/product/0201633612/
文章来源:https://dev.to/documatic/from-problems-to-solutions-understanding-design-patterns-3b7i