Author:Onceday Date:2023年12月5日
漫漫长路,才刚刚开始…
全系列文章请查看专栏: 设计模式_Once_day的博客-CSDN博客。
参考文档:
设计模式的概念最早源自于建筑学家克里斯托弗·亚历山大在1970年代的研究。他尝试找出建筑设计中的一些常见问题和解决方案,然后将这些解决方案记录为“模式”。这个概念后来被软件工程界接纳,尤其是在Erich Gamma, Richard Helm, Ralph Johnson和John Vlissides(被称为“四人帮”)的《设计模式:可复用面向对象软件的基础》一书中得到了深入的探讨。
设计模式是为了解决在软件设计中经常遇到的一些特定问题提供的一种模板性的解决方案。它们可以帮助设计者快速有效地解决这些问题,提高代码的可读性、可复用性和可维护性。设计模式可以被视为一种通用语言,让软件开发者能够有效地交流有关设计的问题和解决方案。
在实际应用中,设计模式的实践过程通常包括以下步骤:
设计模式是一个强大的工具,但也需要谨慎使用。不是所有的问题都需要使用设计模式来解决,而且过度使用设计模式可能会导致代码过于复杂。
设计模式通常由以下四个基本元素组成:
模式名称(Pattern Name):每个设计模式都有一个唯一的名字,通常以其用途或行为来命名,如“单例”、“观察者”或“工厂方法”。
问题(Problem):问题部分描述了在何种场景下应该使用该模式。它可能包括设计中的特定问题和需求。
解决方案(Solution):解决方案部分描述了设计的组成部分,它们的关系以及各自的职责和协作方式。解决方案并不是具体的代码,而是以设计问题的形式,可以在许多不同的情况下实施。
效果(Consequences):描述了应用模式的效果和权衡之处。它们是对设计可重用性、灵活性等方面影响的系统性评价。
描述一个设计模式通常会涉及到以下方面:
模式名(Pattern Name):模式的名称应当简洁,并且能清楚地反映出模式的主要功能或概念。
分类(Classification):设计模式通常被分为创建型、结构型和行为型三种类型。创建型模式关注对象的创建机制,结构型模式关注类和对象的组合,而行为型模式关注对象之间的通信。
意图(Intent):这部分简单清晰地描述了模式的主要目的和主要作用。
动机(Motivation):动机部分提供一个实例,解释了模式如何在实际情况中解决问题。
适用性(Applicability):这部分描述了在何种情况下应该使用模式。
结构(Structure):这部分通常包括类图和交互图,描绘了模式的基本结构和交互。
参与者(Participants):这部分描述了模式中的各个角色(通常是类或者对象),以及他们在模式中的责任和行为。
协作(Collaborations):描述了参与者如何协作以完成他们的职责和实现模式的目的。这部分解释了参与者之间的交互和协作方式。
效果(Consequences):描述了模式的优点和缺点,以及使用模式可能会带来的影响。
实现(Implementation):这部分提供了一些关于如何在特定语言中实现模式的建议和注意事项。
设计模式可以根据两个维度进行分类:目的(Purpose)和范围(Scope)。这两个维度提供了一种有用的方式来理解、学习和比较不同的设计模式。
**目的(Purpose)**划分主要用于描述模式主要用于完成什么任务,它分为三个子类别:
**范围(Scope)**则指设计模式是主要用于类的哪一方面,它分为两个子类别:
这两种维度组合之后,可以如下理解:
以下是一些常见的设计模式,按照创建型、结构型和行为型三类来进行分类:
(1) 创建型设计模式:
工厂模式(Factory Pattern): 提供一个创建对象的接口,让其子类决定实例化哪一个类。工厂方法让类把实例化推迟到子类。
抽象工厂模式(Abstract Factory Pattern): 提供一个接口,让该接口负责创建一系列"相关或者相互依赖的对象",无需指定它们具体的类。
单例模式(Singleton Pattern): 确保一个类只有一个实例,并提供一个全局访问点。
建造者模式(Builder Pattern): 使用多个简单的对象一步一步构建成一个复杂的对象。
原型模式(Prototype Pattern): 通过复制现有的实例来创建新的实例。
(2) 结构型设计模式:
适配器模式(Adapter Pattern): 转换一个接口到另一个接口,使得原本由于接口不兼容无法一起工作的类可以一起工作。
装饰器模式(Decorator Pattern): 动态地给一个对象添加一些额外的职责,而不影响从这个类派生的其他对象。
代理模式(Proxy Pattern): 为其他对象提供一个代理,以控制对这个对象的访问。
外观模式(Facade Pattern): 提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
桥接模式(Bridge Pattern): 将抽象部分与实现部分分离,使它们都可以独立地变化。
组合模式(Composite Pattern): 允许你将对象组合成树形结构来表示"部分-整体"的层次结构。
享元模式(Flyweight Pattern): 通过共享技术有效地支持大量的细粒度对象。
(3) 行为型设计模式:
策略模式(Strategy Pattern): 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
模板方法模式(Template Method Pattern): 定义一个操作中的算法的骨架,将一些步骤延迟到子类中。
观察者模式(Observer Pattern): 当一个对象的状态发生改变时,其相关依赖对象会被自动通知。
迭代器模式(Iterator Pattern): 提供一种方法访问一个容器对象中的各个元素,而又不需暴露该对象的内部细节。
责任链模式(Chain of Responsibility Pattern): 为请求创建了一个接收者对象的链。
命令模式(Command Pattern): 将一个请求封装为一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
备忘录模式(Memento Pattern): 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后就可将该对象恢复到原始状态。
访问者模式(Visitor Pattern): 在不改变类的前提下,定义作用于某种数据结构中的各元素的新操作。
中介者模式(Mediator Pattern): 用一个中介者对象封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
解释器模式(Interpreter Pattern): 给定一种语言,定义它的语法的表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
状态模式(State Pattern): 允许一个对象在其内部状态改变时改变它的行为。
选择适合的设计模式通常依赖于几个关键因素,包括你面对的问题类型、你的应用程序或系统的特定需求以及你想要实现的扩展性和可维护性目标。以下是选择设计模式时可以遵循的几个步骤:
明确问题和需求:
了解设计模式分类:
研究相关的设计模式:
评估案例适用性:
考虑长期维护:
原则指导:
考虑已有的实践:
评估团队熟悉度:
实施和反馈:
使用设计模式基本上是识别你的软件设计中出现的共同问题,并应用一种经过时间检验,得到广泛认可的标准解决方案。以下是如何在实践中使用设计模式的步骤:
识别问题,在你的设计中寻找可以通过已知设计模式解决的问题。这可能是关于如何创建对象、如何组织复杂的结构,或者如何协调不同对象之间的交互。
选择合适的设计模式,一旦你识别出问题,就可以从适合的设计模式中做出选择。选择时,需要考虑模式是否适应你的问题,以及它是否与你的项目需求和目标相符。
了解设计模式,在实施前,彻底理解所选模式的结构、参与者和协作方式。设计模式通常有类图和示例代码,这些都是理解模式的好资源。
应用设计模式,将设计模式的结构应用到你的代码中。这通常涉及创建接口和抽象类,以及定义类和方法,使其遵循模式的模板。
调整以适应你的具体情况,很少有设计模式可以不经修改直接应用。通常,你需要调整它们以适应你的应用程序的具体需求。
验证与迭代,实施设计模式后,验证它是否解决了初始问题并且没有引入任何新问题。基于反馈,可能需要进行微调。
下面以单例模式来作为示例,展示如何使用设计模式:
假设你有一个配置管理器,它在应用程序中多处被调用,但你希望在运行时始终只有一个实例。
识别问题:
选择设计模式:
了解单例模式:
应用设计模式:
new
关键字实例化。调整以适应具体情况:
验证与迭代:
Smalltalk 是一种高级、动态、纯面向对象的编程语言,它在 1970 年代由 Xerox PARC(帕洛阿尔托研究中心)开发。Smalltalk 对计算机科学和编程语言设计产生了深远影响,它是面向对象编程和开发环境的先驱。
以下是 Smalltalk 的一些主要特点:
纯面向对象:在 Smalltalk 中,几乎所有的东西都是对象,包括数字、函数和线程等。所有的操作都是通过向对象发送消息来完成的。
动态类型:Smalltalk 是动态类型的语言,这意味着你不需要(也不能)在编译时声明变量的类型。对象的类型在运行时决定。
图形开发环境:Smalltalk 提供了一个完整的图形开发环境,其中包括代码编辑器、调试器、对象浏览器和界面构建器等。这个环境是交互式的,你可以在运行程序的同时修改和调试代码。
垃圾收集:Smalltalk 自动管理内存,程序员不需要手动分配和释放内存。
反射:Smalltalk 支持高级的反射机制。你可以在运行时检查和修改对象的内部状态和行为。
图形用户界面:Smalltalk 提供了一套用于创建图形用户界面的工具和库。
以下是一个简单的 Smalltalk 程序,它计算并打印出前 10 个自然数的和:
| sum |
sum := 0.
1 to: 10 do: [:i | sum := sum + i].
Transcript show: sum.
Smalltalk 的语法非常简洁和一致,但是它与 C、Java 和 Python 等主流语言有很大的不同,可能需要一些时间来适应。尽管 Smalltalk 的使用并不广泛,但是学习 Smalltalk 可以帮助你更深入地理解面向对象编程和动态语言的概念。
这些都是一些重要的面向对象编程系统或语言,每个都有其独特的特性和优点。
CLOS (Common Lisp Object System),CLOS 是 Common Lisp 的对象系统,它为这种强大的动态编程语言提供了面向对象的特性。CLOS 的一个重要特性是多方法(multi-methods),这意味着方法不仅可以基于其接收者的类型,而且还可以基于其其他参数的类型进行分派。此外,CLOS 支持类和方法的动态修改,这为开发者提供了极大的灵活性。
Dylan,一种多范式编程语言,它结合了函数式编程和面向对象编程的特性。Dylan 的语法类似于 ALGOL 和 Pascal,但它的对象系统包含了许多高级特性,如多方法、类的多重继承和元编程。尽管 Dylan 的使用并不广泛,但它对编程语言设计的影响力不可忽视。
Self,一种基于原型的编程语言,它是 JavaScript 和 Lua 等语言的灵感来源。在 Self 中,所有的值都是对象,并且类的概念被完全消除。相反,新的对象是通过复制和修改现有的对象(称为原型)来创建的。Self 还引入了一种叫做 “just-in-time” (JIT) 的编译技术,这种技术现在被广泛用于许多编程语言的实现中。