工厂设计模式(Factory Pattern)
定义
一种创建对象的软件设计模式,它提供了一种将对象的创建过程封装在一个共同的接口 或基类背后的方法。该模式用于解决在创建对象时所涉及的复杂性和依赖关系。
核心思想
- 工厂设计模式通过定义一个公共的工厂接口,该接口包含一个用于创建对象的方法。
- 具体的工厂类实现这个接口,并根据特定的要求返回相应的对象实例。
- 这样,在客户端代码中,只需与工厂接口进行交互,而不需要直接实例化具体的对象类。
三种类型
根据工厂的复杂程度可以分成:简单工厂模式、工厂方法模式和抽象工厂模式
- 简单工厂模式 (Simple Factory Pattern):由一个工厂类根据参数来决定创建哪一种产品类的实例。客户端只需传递相应的参数给工厂类,不需要关心具体的实例化过程。
- 工厂方法模式 (Factory Method Pattern):定义一个用于创建对象的接口,但将具体的对象创建延迟到子类中进行。每个具体的子类都可以定义自己的对象创建逻辑,从而实现了解耦和扩展性。
- 抽象工厂模式 (Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象 的接口,而无需指定它们具体的类。客户端通过与抽象工厂及其产品接口交互,从而使系统在不同具体工厂的情况下能够创建出不同系列的产品。
不同点和相同点
- 随着业务复杂度的增加,我们需要按照实际需求选用简单工厂模式、工厂方法模式、抽象工厂模式;三种工厂模式独有特点分别为:
- 不需要关心具体的实例化过程 -> 对象创建延迟到子类中进行 -> 创建一系列相关或相互依赖对象
- 共同特点:客户端代码与具体对象的创建过程解耦,提高了代码的可维护性和灵活性
简单工厂模式(Simple Factory Pattern)
简单工厂模式定义
- 一种创建对象的设计模式,它由一个具体的工厂类负责根据客户端的需求创建相应的产品对象。
简单工厂模式参与者
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 工厂类 (Factory):负责创建产品对象的工厂类。它通常包含一个静态方法,根据传入的参数来实例化并返回不同的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 抽象产品类(Product):定义了产品对象的共同接口或基类。具体的产品类都必须实现这个接口或继承这个基类。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 具体产品类(Concrete Product):实际的产品类,实现了抽象产品类定义的接口或继承了抽象产品类的基类。
简单工厂模式的工作流程
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 客户端通过调用工厂类的静态方法来请求创建产品对象,传入相应的参数。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 工厂类根据客户端传入的参数,决定实例化哪个具体产品类的对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 工厂类创建具体产品类的对象,并将其返回给客户端。
简单工厂模式示例
typescript
// 定义抽象产品类
abstract class Product {
abstract use(): void;
}
// 具体产品类A
class ConcreteProductA extends Product {
use() {
console.log("使用具体产品A");
}
}
// 具体产品类B
class ConcreteProductB extends Product {
use() {
console.log("使用具体产品B");
}
}
// 工厂类
class Factory {
// 静态方法,根据传入的参数创建并返回具体产品对象
static createProduct(type: string): Product {
switch (type) {
case "A":
return new ConcreteProductA();
case "B":
return new ConcreteProductB();
default:
throw new Error("无效的产品类型");
}
}
}
// 客户端代码
const productA = Factory.createProduct("A"); // 创建具体产品A的对象
productA.use(); // 使用具体产品A
const productB = Factory.createProduct("B"); // 创建具体产品B的对象
productB.use(); // 使用具体产品B
工厂方法模式(Factory Method Pattern)
工厂方法模式定义
- 一种创建对象的设计模式,它通过定义一个用于创建对象的接口 ,但将具体的对象创建延迟到子类中进行。
- 每个具体的子类都可以定义自己的对象创建逻辑,从而实现了解耦和扩展性。
工厂方法模式参与者
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 抽象产品类(Product):定义了产品对象的共同接口或基类。具体的产品类都必须实现这个接口或继承这个基类。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 具体产品类(Concrete Product):实际的产品类,实现了抽象产品类定义的接口或继承了抽象产品类的基类。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 抽象工厂类(Factory):定义了创建产品对象的接口。它通常包含一个抽象的工厂方法,该方法由具体的子类来实现,用于创建具体的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{blue}{4.} </math>4. 具体工厂类(Concrete Factory):实现了抽象工厂类定义的工厂方法,负责创建具体的产品对象。
工厂方法模式工作流程
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 客户端通过调用具体的工厂类的工厂方法来请求创建产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 具体的工厂类根据客户端的请求,创建相应的具体产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 具体的工厂类返回创建的具体产品对象给客户端。
工厂方法模式示例
typescript
// 抽象产品类
interface Product {
use(): void;
}
// 具体产品类A
class ConcreteProductA implements Product {
use() {
console.log("使用具体产品A");
}
}
// 具体产品类B
class ConcreteProductB implements Product {
use() {
console.log("使用具体产品B");
}
}
// 抽象工厂类
abstract class Factory {
abstract createProduct(): Product;
// 其他操作...
}
// 具体工厂类A
class ConcreteFactoryA extends Factory {
createProduct(): Product {
return new ConcreteProductA();
}
// 其他操作...
}
// 具体工厂类B
class ConcreteFactoryB extends Factory {
createProduct(): Product {
return new ConcreteProductB();
}
// 其他操作...
}
// 客户端代码
const factoryA: Factory = new ConcreteFactoryA();
const productA: Product = factoryA.createProduct();
productA.use(); // 使用具体产品A
const factoryB: Factory = new ConcreteFactoryB();
const productB: Product = factoryB.createProduct();
productB.use(); // 使用具体产品B
对比:简单工厂模式和工厂方法模式
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 结构差异:
- 简单工厂模式(Simple Factory Pattern)使用一个工厂类负责创建所有的产品对象。客户端通过传递参数给工厂类来获取特定类型的产品对象。
- 工厂方法模式(Factory Method Pattern)将具体的对象创建延迟到子类中进行。每个具体子类都有自己的工厂方法,用于创建相应的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 类型扩展性:
- 简单工厂模式在添加新的产品时需要修改工厂类的代码,违反了开闭原则。工厂类承担了过多的责任,当产品种类较多时,可能导致工厂类的代码变得复杂。
- 工厂方法模式允许添加新的产品类而无需修改已有的工厂类或客户端代码。每个产品类都对应一个具体的工厂类,这种结构更加可扩展。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 灵活性差异:
- 简单工厂模式提供了一种集中创建对象的方式,适用于对象创建比较简单且不经常发生变化的情况。但当需求变化并需要添加新的产品时,需要修改工厂类的代码。
- 工厂方法模式将对象的创建委托给子类,每个具体工厂类负责创建自己特定的产品。这种结构更加灵活,适用于需求经常变化且需要添加新的产品的情况。
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式定义
- 一种创建对象的设计模式,它提供一个用于创建一系列相关或依赖对象的接口,而无需指定具体的类。
- 通过使用抽象工厂模式,客户端代码可以创建与特定产品族相关的对象,而不需要关注具体对象的创建细节。
抽象工厂模式参与者
$\color{blue}{1.} 抽象工厂 (Abstract Factory):定义了一个创建一系列相关产品的接口。它通常包含多个抽象的工厂方法,每个方法负责创建一个不同类型的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 具体工厂(Concrete Factory):实现了抽象工厂定义的接口,负责创建具体的产品对象。每个具体工厂类对应一个产品族,其中的工厂方法会创建相应的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 抽象产品(Abstract Product):定义了产品对象的共同接口或基类。具体的产品类都必须实现这个接口或继承这个基类。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{blue}{4.} </math>4. 具体产品(Concrete Product):实际的产品类,实现了抽象产品类定义的接口或继承了抽象产品类的基类。
抽象工厂模式工作流程
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 客户端通过调用具体的工厂类的工厂方法来请求创建产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 具体的工厂类根据客户端的请求,创建相应的具体产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 具体的工厂类返回创建的具体产品对象给客户端。
抽象工厂模式示例
typescript
// 定义抽象电脑工厂接口
interface ComputerFactory {
createCPU(): CPU;
createRAM(): RAM;
}
// 具体品牌工厂 - 戴尔电脑工厂
class DellComputerFactory implements ComputerFactory {
createCPU() {
return new DellCPU();
}
createRAM() {
return new DellRAM();
}
}
// 具体品牌工厂 - 惠普电脑工厂
class HPComputerFactory implements ComputerFactory {
createCPU() {
return new HPCPU();
}
createRAM() {
return new HPRAM();
}
}
// 抽象产品类 - CPU
class CPU {}
// 具体产品类 - 戴尔CPU
class DellCPU extends CPU {}
// 具体产品类 - 惠普CPU
class HPCPU extends CPU {}
// 抽象产品类 - RAM
class RAM {}
// 具体产品类 - 戴尔RAM
class DellRAM extends RAM {}
// 具体产品类 - 惠普RAM
class HPRAM extends RAM {}
// 使用抽象工厂模式创建并使用电脑
const dellFactory = new DellComputerFactory();
const hpFactory = new HPComputerFactory();
const dellCPU = dellFactory.createCPU();
const dellRAM = dellFactory.createRAM();
const hpCPU = hpFactory.createCPU();
const hpRAM = hpFactory.createRAM();
console.log(dellCPU); // DellCPU {}
console.log(dellRAM); // DellRAM {}
console.log(hpCPU); // HPCPU {}
console.log(hpRAM); // HPRAM {}
对比:抽象工厂模式和工厂方法模式
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. 目标对象不同:
- 抽象工厂模式的目标是创建一系列相关或依赖的对象,这些对象通常属于不同的产品族。
- 工厂方法模式的目标是创建单个对象,这个对象属于一个特定的产品等级结构。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 关注点不同:
- 抽象工厂模式关注整体的产品族创建,强调一系列相关产品之间的关联性(如按钮、文本框和复选框等组成的界面)。
- 工厂方法模式关注单个产品的创建,强调一个具体产品类的创建过程。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 结构差异:
- 抽象工厂模式中,抽象工厂接口定义了一系列抽象工厂方法,每个方法负责创建一个不同类型的产品对象。具体的工厂类实现了抽象工厂接口,并负责创建具体产品类的对象。
- 工厂方法模式中,抽象工厂类定义了一个抽象的工厂方法,由具体的子类实现该方法来创建具体的产品对象。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{blue}{4.} </math>4. 扩展性方面:
- 抽象工厂模式支持产品族的扩展。当需要添加新的产品族时,需要创建相应的具体工厂类和产品类。
- 工厂方法模式支持单个产品等级结构的扩展。当需要添加新的产品类时,只需创建相应的具体产品类和工厂类。
单个产品 对比 产品族
工厂方法模式适用于创建单个对象,强调一个具体产品类的创建过程,如下面的代码所示
- 在下面的代码中一个 shapeFactory 只有一个生产方法(createShape),只生产一种产品(Shape 类);
- 而抽象工厂 DellComputerFactory 则可以生产 Dell 品牌的两种产品(CPU 和 RAM),也拥有两个生产方法(createCPU 和 createRAM)。
- 相比之下,显然抽象工厂方法更加适合复杂业务需求。
typescript
// 抽象形状工厂接口
interface ShapeFactory {
createShape(): Shape;
}
// 具体形状工厂 - 圆形工厂
class CircleFactory implements ShapeFactory {
createShape() {
return new Circle();
}
}
// 具体形状工厂 - 矩形工厂
class RectangleFactory implements ShapeFactory {
createShape() {
return new Rectangle();
}
}
// 抽象产品类 - 形状
class Shape {}
// 具体产品类 - 圆形
class Circle extends Shape {}
// 具体产品类 - 矩形
class Rectangle extends Shape {}
// 使用工厂方法模式创建并使用形状
const circleFactory = new CircleFactory();
const rectangleFactory = new RectangleFactory();
const circle = circleFactory.createShape();
const rectangle = rectangleFactory.createShape();
console.log(circle); // Circle {}
console.log(rectangle); // Rectangle {}
应用场景
<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{blue}{1.} </math>1. UI组件库 :在开发UI组件库时,可以使用工厂模式来创建不同类型的组件实例。比如,一个按钮组件工厂可以根据传入的参数(如按钮类型、大小等)创建相应的按钮实例。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{blue}{2.} </math>2. 数据库连接池 :在使用数据库时,可以使用工厂模式来管理数据库连接的创建和复用。通过使用连接池工厂,可以提前创建一定数量的数据库连接,并在需要时分配给请求,避免频繁创建和销毁数据库连接。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{blue}{3.} </math>3. 日志记录器 :在日志记录系统中,可以使用日志工厂来创建不同类型的日志记录器。根据日志级别或其他条件,工厂可以创建相应的文件记录器、数据库记录器或网络记录器。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{blue}{4.} </math>4. 文件格式转换器 :在处理文件格式转换时,可以使用工厂模式来创建不同类型的转换器。例如,可以根据文件类型的不同,使用不同的转换器工厂来创建PDF转换器、图像转换器或音频转换器。
<math xmlns="http://www.w3.org/1998/Math/MathML"> 5. \color{blue}{5.} </math>5. 游戏角色创建器 :在游戏开发中,可以使用工厂模式来创建不同类型的游戏角色。通过角色工厂,可以根据角色类型的不同,创建战士、法师或射手等不同的游戏角色实例。
关键词记忆
<math xmlns="http://www.w3.org/1998/Math/MathML"> 模式 \color{orange}{模式} </math>模式 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 关键字 \color{orange}{关键字} </math>关键字 |
---|---|
<math xmlns="http://www.w3.org/1998/Math/MathML"> 简单工厂 \color{grey}{简单工厂} </math>简单工厂 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 解耦 \color{lightgreen}{解耦} </math>解耦 |
<math xmlns="http://www.w3.org/1998/Math/MathML"> 工厂方法 \color{grey}{工厂方法} </math>工厂方法 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 延时 \color{lightgreen}{延时} </math>延时 |
<math xmlns="http://www.w3.org/1998/Math/MathML"> 抽象工厂 \color{grey}{抽象工厂} </math>抽象工厂 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 系列 \color{lightgreen}{系列} </math>系列 |