[关闭]
@TryLoveCatch 2023-03-07T08:37:26.000000Z 字数 7621 阅读 440

Java知识体系之设计模式

Java知识体系


指标

设计的两个指标:

原则

封装变化的内容

找到程序中的变化内容并将其与不变的内容区分开。
该原则的主要目的是将变更造成的影响最小化。

方法层面的封装

类层面的封装

面向接口进行开发,而不是面向实现

面向接口进行开发, 而不是面向实现; 依赖于抽象类 型, 而不是具体类。
如果无需修改已有代码就能轻松对类进行扩展, 那就可以说 这样的设计是灵活的。

组合优于继承

继承可能是类之间最明显、 最简便的代码复用方式

SOLID

设计模式

创建性模式

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

工厂方法

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

UML


1. 产品(Product)将会对接口进行声明。对于所有由创建者及 其子类构建的对象, 这些接口都是通用的。
2. 具体产品(Concrete Products)是产品接口的不同实现。
3. 创建者(Creator)类声明返回产品对象的工厂方法。该方法
的返回对象类型必须与产品接口相匹配。
4. 具体创建者(Concrete Creators) 将会重写基础工厂方法, 使其返回不同类型的产品。

注意, 并不一定每次调用工厂方法都会创建新的实例。 工厂 方法也可以返回缓存、 对象池或其他来源的已有对象。

例子

https://refactoringguru.cn/design-patterns/factory-method/java/example#example-0

适合场景
优缺点

抽象工厂

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

UML


1. 抽象产品(Abstract Product)为构成系列产品的一组不同但 相关的产品声明接口。
2. 具体产品(Concrete Product)是抽象产品的多种不同类型实 现。所有变体(维多利亚/现代)都必须实现相应的抽象产品
(椅子/沙发)。
3. 抽象工厂(Abstract Factory)接口声明了一组创建各种抽象
产品的方法。
4. 具体工厂(Concrete Factory)实现抽象工厂的构建方法。每 个具体工厂都对应特定产品变体, 且仅创建此种产品变体。
5. 客户端(Client)只 需通过抽象接口调用工厂和产品对象, 就能与任何具体工厂/ 产品变体交互。

例子


https://refactoringguru.cn/design-patterns/abstract-factory/java/example#example-0

适合场景

通常有一个“组”的概念,类似于代码里面的,macOS对应一组ui(button、checkbox),window对应一组。

优缺点

生成器

生成器是一种创建型设计模式, 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建 代码生成不同类型和形式的对象。

UML


1. 生成器(Builder)接口声明在所有类型生成器中通用的产品 构造步骤。
2. 具体生成器(Concrete Builders)提供构造过程的不同实现。
具体生成器也可以构造不遵循通用接口的产品。
3. 产品(Products)是最终生成的对象。由不同生成器构造的 产品无需属于同一类层次结构或接口。
4. 主管(Director)类定义调用构造步骤的顺序,这样你就可以 创建和复用特定的产品配置。
5. 客户端(Client)必须将某个生成器对象与主管类关联。一 般情况下, 你只需通过主管类构造函数的参数进行一次性关 联即可。 此后主管类就能使用生成器对象完成后续所有的构 造任务。 但在客户端将生成器对象传递给主管类制造方法时 还有另一种方式。 在这种情况下, 你在使用主管类生产产品 时每次都可以使用不同的生成器。

例子

适合场景
优缺点

原型

原型是一种创建型设计模式,使 你能够复制已有对象,而又无需 使代码依赖它们所属的类。

UML

  1. 原型(Prototype)接口将对克隆方法进行声明。在绝大多数 情况下, 其中只会有一个名为 clone 克隆 的方法。
  2. 具体原型(Concrete Prototype)类将实现克隆方法。除了将 原始对象的数据复制到克隆体中之外, 该方法有时还需处理 克隆过程中的极端情况, 例如克隆关联对象和梳理递归依赖 等等。
  3. 客户端(Client)可以复制实现了原型接口的任何对象。
例子

适合场景
优缺点

单例

单例是一种创建型设计模式, 让你能够保证一个类只有一 个实例,并提供一个访问该 实例的全局节点。

UML

  1. 单例(Singleton)类声明了一个名为 getInstance 获取实 例 的静态方法来返回其所属类的一个相同实例。
例子
适合场景
优缺点

结构性模式

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

适配器

适配器是一种结构型设计模式, 它能使接口不兼容的对象能够 相互合作。

UML


1. 客户端(Client)是包含当前程序业务逻辑的类。
2. 客户端接口(Client Interface)描述了其他类与客户端代码
合作时必须遵循的协议。
3. 服务(Service)中有一些功能类(通常来自第三方或遗留系 统)。 客户端与其接口不兼容, 因此无法直接调用其功能。
4. 适配器(Adapter)是一个可以同时与客户端和服务交互的 类: 它在实现客户端接口的同时封装了服务对象。 适配器接 受客户端通过适配器接口发起的调用, 并将其转换为适用于 被封装服务对象的调用。
5. 客户端代码只需通过接口与适配器交互即可, 无需与具体的 适配器类耦合。 因此, 你可以向程序中添加新类型的适配器 而无需修改已有代码。 这在服务类的接口被更改或替换时很 有用: 你无需修改客户端代码就可以创建新的适配器类。

例子

适合场景
优缺点

桥接

桥接是一种结构型设计模式, 可将一个大类或一系列紧密 相关的类拆分为抽象和实现 两个独立的层次结构,从而 能在开发时分别使用。

UML


1. 抽象部分(Abstraction)提供高层控制逻辑,依赖于完成底 层实际工作的实现对象。
2. 实现部分(Implementation)为所有具体实现声明通用接口。 抽象部分仅能通过在这里声明的方法与实现对象交互。
抽象部分可以列出和实现部分一样的方法, 但是抽象部分通 常声明一些复杂行为, 这些行为依赖于多种由实现部分声明 的原语操作。
3. 具体实现(Concrete Implementations)中包括特定于平台的 代码。
4. 精确抽象(Refined Abstraction)提供控制逻辑的变体。与其 父类一样, 它们通过通用实现接口与不同的实现进行交互。
5. 通常情况下,客户端(Client)仅关心如何与抽象部分合作。 但是, 客户端需要将抽象对象与一个实现对象连接起来。

例子

适合场景
优缺点

组合

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

UML


1. 组件(Component)接口描述了树中简单项目和复杂项目所 共有的操作。
2. 叶节点(Leaf)是树的基本结构,它不包含子项目。 一般情况下, 叶节点最终会完成大部分的实际工作, 因为它
们无法将工作指派给其他部分。
3. 容器(Container)——又名“组合(Composite)”——是包含叶 节点或其他容器等子项目的单位。 容器不知道其子项目所属 的具体类, 它只通过通用的组件接口与其子项目交互。容器接收到请求后会将工作分配给自己的子项目, 处理中间
结果, 然后将最终结果返回给客户端。
4. 客户端(Client)通过组件接口与所有项目交互。因此,客 户端能以相同方式与树状结构中的简单或复杂项目交互。

例子

适合场景
优缺点

装饰

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

UML


1. 部件(Component)声明封装器和被封装对象的公用接口。
2. 具体部件(Concrete Component)类是被封装对象所属的类。
它定义了基础行为, 但装饰类可以改变这些行为。
3. 基础装饰(Base Decorator)类拥有一个指向被封装对象的引 用成员变量。 该变量的类型应当被声明为通用部件接口, 这 样它就可以引用具体的部件和装饰。 装饰基类会将所有操作 委派给被封装的对象。
4. 具体装饰类(Concrete Decorators)定义了可动态添加到部 件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调 用父类方法之前或之后进行额外的行为。
5. 客户端(Client)可以使用多层装饰来封装部件,只要它能 使用通用接口与所有对象互动即可。

例子

适合场景
优缺点

外观

外观是一种结构型设计模式, 能为程序库、框架或其他复 杂类提供一个简单的接口。

UML


1. 外观(Facade)提供了一种访问特定子系统功能的便捷方式,
其了解如何重定向客户端请求, 知晓如何操作一切活动部件。
2. 创建附加外观(Additional Facade)类可以避免多种不相关 的功能污染单一外观, 使其变成又一个复杂结构。 客户端和 其他外观都可使用附加外观。
3. 复杂子系统(Complex Subsystem)由数十个不同对象构成。 如果要用这些对象完成有意义的工作, 你必须深入了解子系 统的实现细节, 比如按照正确顺序初始化对象和为其提供正 确格式的数据。
子系统类不会意识到外观的存在, 它们在系统内运作并且相 互之间可直接进行交互。
4. 客户端(Client)使用外观代替对子系统对象的直接调用。

例子

适合场景
优缺点

享元

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

UML


1. 享元模式只是一种优化。 在应用该模式之前, 你要确定程序 中存在与大量类似对象同时占用内存相关的内存消耗问题, 并且确保该问题无法使用其他更好的方式来解决。
2. 享元(Flyweight)类包含原始对象中部分能在多个对象中共 享的状态。 同一享元对象可在许多不同情景中使用。 享元中 存储的状态被称为“内在状态”。 传递给享元方法的状态被 称为“外在状态”。
3. 情景(Context)类包含原始对象中各不相同的外在状态。情 景与享元对象组合在一起就能表示原始对象的全部状态。
4. 通常情况下, 原始对象的行为会保留在享元类中。 因此调用 享元方法必须提供部分外在状态作为参数。 但你也可将行为 移动到情景类中, 然后将连入的享元作为单纯的数据对象。
5. 客户端(Client)负责计算或存储享元的外在状态。在客户 端看来, 享元是一种可在运行时进行配置的模板对象, 具体 的配置方式为向其方法中传入一些情景数据参数。
6. 享元工厂(Flyweight Factory)会对已有享元的缓存池进行 管理。 有了工厂后, 客户端就无需直接创建享元, 它们只需 调用工厂并向其传递目标享元的一些内在状态即可。 工厂会 根据参数在之前已创建的享元中进行查找, 如果找到满足条 件的享元就将其返回; 如果没有找到就根据参数新建享元。

例子

适合场景
优缺点

代理

代理是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。

UML


1. 服务接口(Service Interface)声明了服务接口。代理必须遵 循该接口才能伪装成服务对象。
2. 服务(Service)类提供了一些实用的业务逻辑。
3. 代理(Proxy)类包含一个指向服务对象的引用成员变量。代 理完成其任务(例如延迟初始化、 记录日志、 访问控制和缓 存等) 后会将请求传递给服务对象。 通常情况下, 代理会对 其服务对象的整个生命周期进行管理。
4. 客户端(Client) 能通过同一接口与服务或代理进行交互, 所以你可在一切需要服务对象的代码中使用代理。

例子

适合场景
优缺点

行为模式

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

责任链

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

UML


1. 处理者(Handler)声明了所有具体处理者的通用接口。该接 口通常仅包含单个方法用于请求处理, 但有时其还会包含一 个设置链上下个处理者的方法。
2. 基础处理者(Base Handler)是一个可选的类,你可以将所 有处理者共用的样本代码放置在其中。
通常情况下, 该类中定义了一个保存对于下个处理者引用的 成员变量。 客户端可通过将处理者传递给上个处理者的构造 函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。
3. 具体处理者(Concrete Handlers)包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及 是否沿着链传递请求。
处理者通常是独立且不可变的, 需要通过构造函数一次性地 获得所有必要地数据。
4. 客户端(Client)可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非 必须是第一个处理者。

例子
适合场景
优缺点

命令

命令是一种行为设计模式, 它可将请求转换为一个包 含与请求相关的所有信息 的独立对象。该转换让你 能根据不同的请求将方法 参数化、延迟请求执行或 将其放入队列中,且能实 现可撤销操作。

UML
例子
适合场景
优缺点

迭代器

UML
例子
适合场景
优缺点

中介者

UML
例子
适合场景
优缺点

备忘录

UML
例子
适合场景
优缺点

观察者

UML
例子
适合场景
优缺点

状态

UML
例子
适合场景
优缺点

策略

UML
例子
适合场景
优缺点

模板方法

UML
例子
适合场景
优缺点

访问者

UML
例子
适合场景
优缺点

总结

参考

https://refactoringguru.cn/
Android架构演进 · 设计模式· 为什么建议你一定要学透设计模式?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注