抽象工厂模式

Metadata

title: 抽象工厂模式
date: 2022-12-14 15:24
tags:
  - 
categories:
  - 
keywords:
  - 
description: 

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

简介

意图:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

主要解决:
主要解决接口选择的问题。

何时使用:
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决:
在一个产品族里面,定义多个产品。

关键代码:
在一个工厂里聚合多个同类产品。

应用实例:
工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景:
1、QQ 换皮肤,一整套一起换。
2、生成不同操作系统的程序。

注意事项:
产品族难扩展,产品等级易扩展。

模式结构

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

适合应用场景

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

抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品。

- 如果你有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。

- 在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互, 就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。

实现方式

  1. 以不同的产品类型与产品变体为维度绘制矩阵。
  2. 为所有产品声明抽象产品接口。 然后让所有具体产品类实现这些接口。
  3. 声明抽象工厂接口, 并且在接口中为所有抽象产品提供一组构建方法。
  4. 为每种产品变体实现一个具体工厂类。
  5. 在应用程序中开发初始化代码。 该代码根据应用程序配置或当前环境, 对特定具体工厂类进行初始化。 然后将该工厂对象传递给所有需要创建产品的类。
  6. 找出代码中所有对产品构造函数的直接调用, 将其替换为对工厂对象中相应构建方法的调用。

示例

优缺点

title: 优点

- 你可以确保同一工厂生成的产品相互匹配。
- 你可以避免客户端和具体产品代码的耦合。
- 单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
- 开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。

缺点

由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。

与其他模式的关系

在许多设计工作的初期都会使用[[工厂方法模式]] (较为简单, 而且可以更方便地通过子类进行定制), 随后演化为使用[[抽象工厂模式]]、 [[原型模式]]或[[生成器模式]] (更灵活但更加复杂)。

[[生成器模式]]重点关注如何分步生成复杂对象。[[抽象工厂模式]]专门用于生产一系列相关对象。 [[抽象工厂模式]]会马上返回产品, 生成器则允许你在获取产品前执行一些额外构造步骤。

[[抽象工厂模式]]通常基于一组工厂方法, 但你也可以使用原型模式来生成这些类的方法。

当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用[[抽象工厂模式]]来代替[[外观模式]]。

你可以将[[抽象工厂模式]]和[[桥接模式]]搭配使用。 如果由桥接定义的抽象只能与特定实现合作, 这一模式搭配就非常有用。 在这种情况下,[[抽象工厂模式]]可以对这些关系进行封装, 并且对客户端代码隐藏其复杂性。

[[抽象工厂模式]]、[[生成器模式]]和[[原型模式]]都可以用[[单例模式]]来实现。