# 什么是工厂模式?

工厂模式 (Factory Pattern) 是开发中常用的设计模式之一,属于创建型设计模式;跟单例设计模式创建单一实例不同的是,工厂模式是提供创建对象的最佳方式帮助我们按照不同的需求创建产品以达到

“需求” 和 “生产产品” 的解耦

并且工厂模式在创建对象时也

不会对外暴创建对象的过程

并且可以使用同一个共同的接口访问创建对象。

工厂模式的实现主要分为三种:
简单工厂模式 (Simple Factory);
工厂方法模式 (Factory Method);
抽象工厂模式 (Abastract Factorv);

其中简单工厂不在 23 种经典设计模式里;这三种模式从简单到抽象,设计过程越来越复杂但是设计上越来越完美。

# 简单工厂模式

又叫作静态工厂方法模式

我们把被创建的对象称为 “产品”,把创建产品的对象称为 “工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫 “简单工厂模式”。

# 简单工厂模式主要 3 个角色

简单工厂(SimpleFactory)
是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的 - 建产品类的方法可以被外界直接调用,创建所需的产品对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 简单工厂
class SimpleFactory {
public static Product createProduct(String type) {
if (type == null) {
return null;
}
if (type.equalsIgnoreCase("A")) {
return new ConcreteProductA();
} else if (type.equalsIgnoreCase("B")) {
return new ConcreteProductB();
}
return null;
}
}

抽象产品(Product)
是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。

1
2
3
4
// 抽象产品
interface Product {
void show();
}

具体产品(ConcreteProduct)
是简单工厂模式的创建目标。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 具体产品A
class ConcreteProductA implements Product {
public void show() {
System.out.println("This is product A.");
}
}

// 具体产品B
class ConcreteProductB implements Product {
public void show() {
System.out.println("This is product B.");
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
// 客户端调用
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.show(); // 输出 "This is product A."

Product productB = SimpleFactory.createProduct("B");
productB.show(); // 输出 "This is product B."
}
}

# 优缺点

主要优点:

  • 结构简单,调用方便。工厂和产品的职责区分明确。
  • 客户端无需知道所创建具体产品的类名,只需知道参数即可。

主要缺点:

  • 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
  • 不同的产品需要不同额外参数的时候不支持。

# 使用场景

对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

# 工厂模式

工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

# 工厂模式的核心角色

抽象产品(Product):

定义了产品的规范,描述了产品的主要特性和功能。

1
2
3
4
// 抽象产品
interface Animal {
void speak();
}

具体产品(Concrete Product):

实现或继承抽象产品接口的类。每一种产品都有各自的特点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 具体产品A
class Dog implements Animal {
public void speak() {
System.out.println("汪汪汪!");
}
}

// 具体产品B
class Cat implements Animal {
public void speak() {
System.out.println("喵喵喵!");
}
}

抽象工厂(Factory):

声明了创建抽象产品的接口,但由它的子类来确定要实例化的具体产品类。

1
2
3
4
// 工厂接口
interface AnimalFactory {
Animal createAnimal();
}

具体工厂(Concrete Factory):

实现抽象工厂接口,并返回一个等级结构中的具体产品实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 具体工厂A
class DogFactory implements AnimalFactory {
public Animal createAnimal() {
return new Dog();
}
}

// 具体工厂B
class CatFactory implements AnimalFactory {
public Animal createAnimal() {
return new Cat();
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
// 客户端调用
public class Client {
public static void main(String[] args) {
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.speak(); // 输出 "汪汪汪!"

AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.speak(); // 输出 "喵喵喵!"
}
}

在这个例子中,我们定义了一个抽象产品接口 Animal 和两个具体产品类 Dog 和 Cat。然后,我们创建了一个工厂接口 AnimalFactory 和两个具体工厂类 DogFactory 和 CatFactory,它们分别负责创建具体的动物实例。最后,在客户端代码中,我们使用不同的工厂来创建并显示不同类型的动物。

# 优缺点

优点‌:

和 “简单工厂模式” 不同的地方,是加入了 “开放 - 封闭原则”(软件实体类、模块或者函数等等,应该可以扩展,但是不可以修改)规则,将简单工厂的内部判断逻辑,移动到了客户端代码来进行,在扩展新功能的时候,简单工厂模式要修改工厂类,工厂方法模式是只需要修改客户端。

在添加新产品时,无需修改抽象工厂和抽象产品提供的接口,也无需修改客户端代码。只需要添加一个新的具体产品类和对应的具体工厂类,这样系统的可扩展性非常好,符合开闭原则‌

缺点‌:

增加系统复杂度‌:每增加一个新产品,就需要增加一个具体产品类和对应的具体工厂类,这会增加系统的复杂度。系统中类的个数将成对增加,可能会在一定程度上增加编译和运行的开销‌。

# 使用场景

  • 消费者不关心它所要创建对象的类 (产品类) 的时候。
  • 消费者知道它所要创建对象的类 (产品类),但不关心如何创建的时候。

# 抽象工厂模式

抽象工厂模式提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。它是一种比简单工厂和工厂方法更高层次的设计模式。它围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂。提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。

# 抽象工厂的核心角色

抽象产品(Abstract Product):

定义了产品的规范,描述了产品的主要特性和功能。

1
2
3
4
5
6
7
8
// 抽象产品A
interface ProductA {
void show();
}
// 抽象产品B
interface ProductB {
void show();
}

具体产品(Concrete Product):

实现或继承抽象产品接口的类。每一种产品都有各自的特点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 具体产品A1
class ConcreteProductA1 implements ProductA {
public void show() {
System.out.println("This is product A1.");
}
}

// 具体产品A2
class ConcreteProductA2 implements ProductA {
public void show() {
System.out.println("This is product A2.");
}
}
// 具体产品B1
class ConcreteProductB1 implements ProductB {
public void show() {
System.out.println("This is product B1.");
}
}

// 具体产品B2
class ConcreteProductB2 implements ProductB {
public void show() {
System.out.println("This is product B2.");
}
}

抽象工厂(Abstract Factory):

声明了创建抽象产品的接口,由子类确定要生成的具体产品类。

1
2
3
4
5
// 抽象工厂
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}

具体工厂(Concrete Factory):

实现抽象工厂接口,并返回一系列具体产品的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 具体工厂A
class ConcreteFactoryA implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}

// 具体工厂B
class ConcreteFactoryB implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Client {
public static void main(String[] args) {
AbstractFactory factoryA = new ConcreteFactoryA();
ProductA productA1 = factoryA.createProductA();
productA1.show(); // 输出 "This is product A1."
ProductB productB1 = factoryA.createProductB();
productB1.show(); // 输出 "This is product B1."

AbstractFactory factoryB = new ConcreteFactoryB();
ProductA productA2 = factoryB.createProductA();
productA2.show(); // 输出 "This is product A2."
ProductB productB2 = factoryB.createProductB();
productB2.show(); // 输出 "This is product B2."
}
}

在这个例子中,我们定义了两个抽象产品接口 ProductA 和 ProductB,以及它们各自的具体产品类。然后,我们创建了一个抽象工厂接口 AbstractFactory 和两个具体工厂类 ConcreteFactoryA 和 ConcreteFactoryB,它们分别负责创建具体的产品实例。最后,在客户端代码中,我们使用不同的工厂来创建并显示不同类型的产品。

# 优缺点

优点:

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

缺点:

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

# 使用场景

1、QQ 换皮肤,一整套一起换。

2、生成不同操作系统的程序。

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

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

用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服,又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。