23种设计模式
- 🎯 创建型设计模式
- 📌 抽象工厂(Abstract Factory) 设计模式
- 📌 工厂方法(Factory Method)设计模式
- 📌 单例(Singleton)设计模式
- 📌 生成器(Builder)设计模式
- 📌 原型(Prototype)设计模式
- 🎯 结构型设计模式
- 📌 适配器(Adapter)设计模式
- 📌 桥接(Bridge)设计模式
- 📌 组合(Composite)设计模式
- 📌 装饰器(Decorator)设计模式
- 📌 外观(Facade)设计模式
- 📌 享元(Flyweight)设计模式
- 📌 代理(Proxy)设计模式
- 🎯 行为型设计模式
- 📌 责任链(Chain of Responsibility)设计模式
- 📌 命令(Command)设计模式
- 📌 解释器(Interpreter)设计模式
- 📌 迭代器(Iterator)设计模式
- 📌 中介者(Mediator)设计模式
- 📌 备忘录(Memento)设计模式
- 📌 观察者(Observer)设计模式
- 📌 状态(State)设计模式
- 📌 策略(Strategy)设计模式
- 📌 模板方法(Template Method)设计模式
- 📌 访问者(Visitor)设计模式
针对软件设计师考试中设计模式题型,这篇文章对23种设计模式作总结
🎯 创建型设计模式
📌 抽象工厂(Abstract Factory) 设计模式
点击跳转:抽象工厂模式代码实例(Java)
💡 意图
提供一个创建一系列相关或相互依赖的接口,而无需指定他们具体的类
💡 图例
图中绿色虚线是接口实现关系,白色虚线为实例化创建
💡 适用场景
-
一个系统要独立于它的产品的创建,组合和表示时;
-
一个系统要由多个产品系列中的一个来配置时;
-
需要强调一系列相关的产品对象的设计以便进行联合使用时;
-
提供一个产品类库,而只想显示它们的接口而不是实现时。
📌 工厂方法(Factory Method)设计模式
点击跳转:工厂方法模式代码实例(Java)
💡 意图
提供一个创建对象的接口,但由子类决定要实例化的具体类。工厂方法使得类的实例化延迟到子类。
💡 图例
图中绿色虚线是接口实现关系,l蓝色实线表示抽象类继承,白色虚线为实例化创建
💡 适用场景
-
当一个类无法预见它所需要的对象的具体类型时,使用工厂方法模式。
-
当一个类希望将创建对象的责任委托给子类,以便于扩展时。
-
当需要避免在代码中直接依赖具体类,而是通过抽象接口或基类进行操作时。
-
当一组相关的产品需要动态创建,但只希望暴露其抽象接口时。
📌 单例(Singleton)设计模式
点击跳转:单例模式代码实例(Java)
💡 意图
确保一个类只有一个实例,并提供全局访问点来获取该实例。单例模式常用于管理共享资源或需要全局唯一对象的场景。
💡 图例
SingletonPattern没有实例化,只能通过getInstance()访问
💡 适用场景
-
当一个类只能有一个实例时,如配置管理器、日志对象、线程池等。
-
当需要全局访问点时,如访问数据库连接池或缓存管理器。
-
避免对象创建时浪费资源,如只需要一个共享实例而不需要重复创建时。
-
当类的实例化和使用分离时,可以通过延迟实例化来优化性能。
📌 生成器(Builder)设计模式
点击跳转:生成器模式代码实例(Java)
💡 意图
将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。生成器模式允许通过逐步构建的方式,灵活创建复杂对象。
💡 图例
💡 适用场景
-
当对象的构建过程复杂,涉及多个步骤时,如构建一个多层次的复杂对象。
-
当需要创建不同表现形式的复杂对象时,但构建过程相同时。
-
当需要在不同环境下构建不同的产品时,如不同的操作系统或数据库配置等。
-
当客户端只需要关心最终对象的类型,而不关心构建过程时,可以通过生成器模式提供更好的封装和灵活性。
📌 原型(Prototype)设计模式
点击跳转:原型模式代码实例(Java)
💡 意图
通过复制现有的对象来创建新的对象,而不是通过实例化新对象。原型模式允许在运行时动态地克隆对象,从而简化对象的创建过程,尤其适用于复杂对象的创建。
💡 图例
💡 适用场景
-
当创建对象的成本较高,且相似对象可以通过克隆来获得时。
-
当需要大量相似对象,但是其细节有所不同时,可以通过原型模式创建这些对象。
-
当类的构造过程复杂,但可以通过克隆现有对象来快速创建新实例时。
-
当对象的状态或行为需要从现有对象进行复制,而不需要重新构造时。
🎯 结构型设计模式
📌 适配器(Adapter)设计模式
点击跳转:适配器模式代码实例(Java)
💡 意图
将一个类的接口转换成客户端所期待的另一个接口,使得原本接口不兼容的类能够一起工作。适配器模式使得不同接口之间可以协同工作,通常用于连接新旧系统。
💡 图例
💡 适用场景
-
当你希望通过现有的接口来访问旧系统中的功能,但这些功能的接口和新的系统不兼容时。
-
当需要使用一些现有的类,但它们的接口不符合要求时,可以通过适配器模式使其兼容。
-
当系统中多个类的接口不一致,且这些类需要协同工作时。
-
当你需要让类具有更灵活的接口,能与不同的外部接口交互时。
📌 桥接(Bridge)设计模式
点击跳转:桥接模式代码实例(Java)
💡 意图
将抽象部分与实现部分分离,使得二者可以独立变化。桥接模式通过引入桥接接口,将抽象部分与实现部分解耦,从而在不改变客户端代码的前提下,改变或扩展系统的实现。
💡 图例
💡 适用场景
-
当需要将抽象部分与其实现部分解耦,使得二者可以独立扩展时。
-
当一个类存在多个变化维度,且每个维度都可能变化时,桥接模式可以减少子类的数量。
-
当需要在不同的操作系统或设备之间共享功能实现时,通过桥接模式实现对不同平台的支持。
-
当类的继承结构较为复杂,导致子类众多时,桥接模式有助于简化设计。
📌 组合(Composite)设计模式
点击跳转:组合模式代码实例(Java)
💡 意图
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式让客户端可以统一地对待单个对象和对象集合,通常用于表示树形结构,如文件系统或组织结构。
💡 图例
💡 适用场景
-
当需要表示“部分-整体”层次结构时,如组织架构、文件目录等。
-
当客户端需要统一地处理单个对象和对象集合时,通过组合模式避免区分对象和容器。
-
当对象数量不确定且层次结构复杂时,组合模式可以简化操作。
-
当你希望构建一个递归树形结构时,如树形菜单、图形组件等。
📌 装饰器(Decorator)设计模式
点击跳转:装饰器模式代码实例(Java)
💡 意图
动态地为对象添加新的功能,而不影响其原有结构。装饰器模式通过将对象包装在一个或多个装饰器中,增强其功能,而无需修改原始类。
💡 图例
💡 适用场景
-
当不希望通过继承来扩展类的功能时,可以使用装饰器模式动态地增加行为。
-
当需要在运行时为对象添加额外功能时,装饰器模式提供比继承更灵活的解决方案。
-
当希望用多个不同的功能装饰同一个对象时,装饰器模式允许自由组合不同的装饰功能。
-
当系统需要遵循开闭原则(OCP),即对扩展开放、对修改封闭时,装饰器模式是理想选择。
📌 外观(Facade)设计模式
点击跳转:外观模式代码实例(Java)
💡 意图
为子系统中的一组接口提供一个统一的接口,外观模式定义了一个高层接口,使得子系统更容易使用。它主要用于简化复杂系统的访问,提高代码的可读性和维护性。
💡 图例
💡 适用场景
-
当系统过于复杂,且外部调用者只需要关注高层逻辑时,外观模式可以提供简单的访问方式。
-
当多个子系统需要被统一管理时,外观模式可以减少直接访问子系统的复杂性。
-
当希望对子系统进行解耦,以便日后修改子系统时,外观模式可以隐藏子系统的细节。
-
当需要提供一个一致的接口,以屏蔽多个子系统的不同实现时,可以使用外观模式。
📌 享元(Flyweight)设计模式
点击跳转:享元模式代码实例(Java)
💡 意图
通过共享对象来减少内存使用,以支持大量细粒度对象的高效使用。享元模式避免了创建重复对象,从而提高性能,尤其适用于资源受限的环境。
💡 图例
💡 适用场景
-
当系统中存在大量相似对象,并且会消耗大量内存时,享元模式可以减少对象数量。
-
当对象的大部分状态是相同的,仅少部分状态有所变化时,可以将不变部分作为享元共享。
-
当创建对象的开销较大,且需要优化性能时,享元模式能够减少对象创建成本。
-
当系统需要支持大量对象但受限于内存资源时,享元模式提供了一种共享机制。
📌 代理(Proxy)设计模式
点击跳转:代理模式代码实例(Java)
💡 意图
为某个对象提供一个代理,以控制对该对象的访问。代理模式用于在访问对象前增加额外的逻辑,例如权限控制、懒加载、日志记录、远程访问等。
💡 图例
💡 适用场景
-
远程代理(Remote Proxy)
: 当需要访问远程对象时,代理模式可以封装网络通信细节,例如 RMI(远程方法调用)。 -
虚拟代理(Virtual Proxy)
: 当对象创建开销较大时,代理可以延迟对象的初始化(懒加载)。 -
保护代理(Protection Proxy)
: 当需要控制对对象的访问权限时,例如不同用户权限访问不同的功能。 -
缓存代理(Cache Proxy)
: 代理对象可以存储访问的结果,避免重复计算,提高性能。 -
智能引用代理(Smart Reference)
: 代理在访问对象时附加额外操作,例如记录日志或统计访问次数。
🎯 行为型设计模式
📌 责任链(Chain of Responsibility)设计模式
点击跳转:责任链模式代码实例(Java)
💡 意图
将多个处理者按顺序连接成一条链,每个处理者都可以处理请求或将其传递给下一个处理者。责任链模式避免了请求发送者与接收者之间的直接耦合,使请求处理更加灵活。
💡 图例
💡 适用场景
-
当请求需要被多个对象处理时,可以使用责任链模式动态决定处理者的顺序。
-
当请求的处理逻辑需要灵活扩展时,责任链模式允许动态增加或修改处理者。
-
当希望降低请求发送者与接收者的耦合度时,责任链模式使得请求者不需要关心具体的处理者。
-
当有多个处理者可以处理请求,但具体由谁处理在运行时决定时,责任链模式提供了一种灵活的解决方案。
📌 命令(Command)设计模式
点击跳转:命令模式代码实例(Java)
💡 意图
将请求封装成对象,以便使用不同的请求、队列或者日志来参数化对象。命令模式允许请求的发送者和接收者解耦,并支持操作的撤销(Undo)和恢复(Redo)。
💡 图例
💡 适用场景
-
当需要将请求封装为对象,以支持撤销(Undo)和恢复(Redo)功能时,命令模式能够很好地管理请求。
-
当系统需要对请求排队、记录日志或支持事务时,命令模式可以灵活处理这些需求。
-
当需要将请求的发送者和执行者解耦时,命令模式提供了一个中间层,使两者不直接交互。
-
当系统需要支持宏命令(批量命令)时,命令模式可以组合多个命令并统一执行。
📌 解释器(Interpreter)设计模式
点击跳转:解释器模式代码实例(Java)
💡 意图
定义一个语言的语法表示,并提供一个解释器来处理该语言的句子。解释器模式用于设计编译器、表达式计算器、规则引擎等,以解析和执行特定的语法规则。
💡 图例
💡 适用场景
-
当需要解析和执行特定语言的语法规则时,解释器模式能够将复杂的语法解析为对象结构。
-
当存在特定的业务规则需要频繁更改或扩展时,解释器模式可以提供灵活的规则定义方式。
-
当系统需要支持不同的表达式计算时,如数学计算、逻辑运算、SQL 解析等,解释器模式是合适的选择。
-
当要构造一个简单的编译器或解释器时,可以使用解释器模式解析语法树并执行相应的操作。
📌 迭代器(Iterator)设计模式
点击跳转:迭代器模式代码实例(Java)
💡 意图
提供一种方法顺序访问集合对象中的元素,而不暴露其内部表示。迭代器模式使得遍历不同集合结构(如数组、链表、树等)时可以使用统一的方式,并且解耦了遍历算法与集合对象的实现。
💡 图例
💡 适用场景
-
当需要遍历集合对象,但不希望暴露集合的内部结构时,迭代器模式可以提供一个统一的访问方式。
-
当需要支持多种遍历方式(正序、倒序、跳跃等)时,迭代器模式允许自定义迭代逻辑。
-
当希望对不同类型的集合结构(如数组、链表、哈希表等)使用相同的遍历接口时,迭代器模式提供了解决方案。
-
当多个对象需要顺序访问集合对象时,迭代器模式可以确保遍历过程的独立性和一致性。
📌 中介者(Mediator)设计模式
点击跳转:中介者模式代码实例(Java)
💡 意图
定义一个中介对象,封装多个对象之间的交互,使对象之间不再相互引用,而是通过中介者进行通信。中介者模式降低了对象之间的耦合度,使得系统更加可扩展和维护。
💡 图例
💡 适用场景
-
当对象之间存在复杂的交互关系时,中介者模式可以简化对象的相互依赖,避免对象之间形成网状结构。
-
当多个对象之间的交互需要统一管理时,中介者模式可以提供一个中心化的管理机制。
-
当对象之间的交互需要动态变化时,中介者模式可以让交互逻辑集中在一个类中,便于修改和扩展。
-
当需要减少类之间的耦合,提高代码的可维护性时,中介者模式是一个不错的选择。
📌 备忘录(Memento)设计模式
点击跳转:备忘录模式代码实例(Java)
💡 意图
备忘录模式在不暴露对象内部状态的情况下,保存对象的状态,以便在需要时恢复到先前的状态。它允许在不破坏封装的情况下保存和恢复对象的状态,适用于需要撤销或恢复功能的场景。
💡 图例
💡 适用场景
-
当系统需要提供撤销(Undo)或恢复(Redo)功能时,备忘录模式能够存储对象的历史状态。
-
当对象状态变化频繁,且需要随时恢复到某个历史状态时,备忘录模式可以有效管理和恢复这些状态。
-
当需要在不破坏封装的情况下,保存对象的状态时,备忘录模式允许保存对象的状态,而不会暴露其实现细节。
-
当需要在某个操作执行后,能够恢复到先前的状态时,备忘录模式非常适用。
📌 观察者(Observer)设计模式
点击跳转:观察者模式代码实例(Java)
💡 意图
定义了一种一对多的依赖关系,使得每当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。观察者模式通常用于事件监听、广播通信等场景,它解耦了被观察者和观察者之间的关系。
💡 图例
💡 适用场景
-
当一个对象的状态变化需要影响其他对象时,且不希望被观察者和观察者之间产生过强的耦合时,观察者模式是理想的解决方案。
-
当多个观察者对象需要响应同一事件的变化时,观察者模式能自动通知所有相关的观察者。
-
当需要提供事件驱动机制时,例如在 GUI 应用程序中,当按钮被点击时,需要通知多个组件进行相应的处理。
-
当一个对象的状态变化需要同时通知多个不同类型的对象时,观察者模式能够提供灵活的通知机制。
📌 状态(State)设计模式
点击跳转:状态模式代码实例(Java)
💡 意图
允许一个对象在其内部状态改变时改变其行为,看起来就像是改变了类。状态模式通过将不同的状态封装成独立的类,使得对象的行为随着状态的不同而变化,避免了大量的条件语句。
💡 图例
💡 适用场景
-
当一个对象的行为依赖于其状态,并且在运行时其状态可能会改变时,状态模式可以更好地组织和管理这些行为。
-
当对象的行为随着状态的改变而变化,且使用条件语句处理这种变化显得繁琐和难以维护时。
-
当系统中存在多种状态转换逻辑,并且每个状态下的行为都需要清晰分离时,状态模式非常适合。
-
当希望避免多个条件判断语句(如 if-else 或 switch)时,状态模式可以将每个状态的行为独立封装,减少复杂度。
📌 策略(Strategy)设计模式
点击跳转:策略模式代码实例(Java)
💡 意图
定义一系列的算法,将每一个算法封装起来,并使它们可以互换。策略模式使得算法的变化独立于使用算法的客户。通过定义策略接口和多个具体的策略实现,策略模式允许客户端在运行时选择不同的算法或行为。
💡 图例
💡 适用场景
-
当系统中存在多个算法(策略)且这些算法可以相互替换时,策略模式提供了一个灵活的方式来封装和选择不同的算法。
-
当需要根据不同的环境或条件来选择不同的行为时,策略模式能够帮助分离选择逻辑和具体算法。
-
当系统中有很多类似的条件语句(如 if-else 或 switch),而这些条件语句负责选择不同算法时,策略模式可以让条件逻辑更加清晰并易于扩展。
-
当算法或行为频繁变化时,策略模式让这些变化更加容易控制和扩展,避免对客户代码的修改。
📌 模板方法(Template Method)设计模式
点击跳转:模板方法模式代码实例(Java)
💡 意图
定义一个操作中的算法骨架,将一些步骤的实现延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下重新定义算法中的某些特定步骤。它主要用于定义一个不变的算法结构,并允许子类去实现其中的某些可变部分。
💡 图例
💡 适用场景
-
当一个算法中有一些不变的步骤,而某些步骤可以由子类改变时,模板方法模式非常适用,它将不变的部分提取到父类中。
-
当多个子类有共同的算法结构,但部分细节需要不同实现时,可以通过模板方法模式来定义统一的框架,并让子类提供不同的实现。
-
当你想在不修改类的情况下,扩展现有算法时,模板方法模式可以通过子类重写方法来进行扩展。
-
当一个操作的步骤是固定的,而某些步骤需要定制化时,模板方法模式帮助将步骤的共同部分和特定实现区分开。
📌 访问者(Visitor)设计模式
点击跳转:访问者模式代码实例(Java)
💡 意图
将数据结构与操作数据的行为分离,使得操作数据的行为可以独立于数据结构变化而变化。访问者模式允许你在不改变对象结构的前提下,增加新的操作。它通常用于需要对一组对象执行一系列操作的场景。
💡 图例
💡 适用场景
-
当需要对一组对象进行操作,但不希望修改对象结构时,访问者模式通过将操作逻辑从对象中抽离出来实现了操作与数据的解耦。
-
当需要在系统中增加新的操作时,访问者模式能够通过添加新的访问者来扩展系统,而无需修改已有的元素类。
-
当需要对元素结构中的对象进行复杂的操作,并且这些操作涉及不同类型的元素时,访问者模式能够简化操作的管理和扩展。
-
当你希望将操作集中管理,而不是让操作逻辑分散在不同的类中时,访问者模式可以帮助集中管理访问操作。
创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️