工厂模式(Factory Pattern)是面向对象编程中最经典、也是最常用的创建型设计模式之一。
简单来说,工厂模式的核心思想就是:将"创建对象"的过程封装起来。对象的使用方不需要知道对象具体是如何被 new 出来的,只需要告诉"工厂"自己需要什么,工厂就会把做好的对象交给你。
之所以这么做,最主要就是解决了对象使用方和创建对象的耦合,在代码层面,客户端无需直接使用 new,对象的创建由工厂负责。否则,当需要使用到一个对象时,自己去 new,就需要考虑到创建这个对象的各种细节,例如构造参数等。
工厂模式有三种:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
首先,既然是工厂模式,那我们先把要生产的产品定义出来,以便后面演示:
java
// 定义产品接口
interface Product {
void getName();
}
class XiaomiComputer implements Product {
@Override
public void getName() {
System.out.println("小米电脑");
}
}
class ApplePhone implements Product {
@Override
public void getName() {
System.out.println("苹果手机");
}
}
工厂模式本质是封装对象创建,客户端只依赖 抽象产品(接口或抽象类) 而不依赖具体类。因此必须有一个抽象产品,工厂方法或抽象工厂才有意义,因此我们定义了 Product 这个接口。
另外,工厂模式是对"创建行为"的设计规范,产品接口的设计由你的业务需求决定,你只需要有个抽象产品接口用于工厂的返回。
简单工厂模式(Simple Factory)
简单工厂模式有时也叫静态工厂模式,但它并不能算是一个正式的设计模式,只是一种常用的对象创建方式(其实就是一个方法)。在简单工厂模式中,通常会有一个工厂类,它根据参数的不同返回不同类型的对象。
使用简单工厂模式甚至都不用定义工厂的接口,直接创建一个实现类即可,你其实就可以将这个简单工厂理解为一个 switch 方法而已:
java
class SimpleFactory {
public static Product createProduct(String type) {
switch (type) {
case "小米电脑": return new XiaomiComputer();
case "苹果手机": return new ApplePhone();
default: return null;
}
}
}
对于产品的使用者来说,需要什么产品仅仅需要传入对应的参数即可:
java
class Customer {
public static void main(String[] args) {
SimpleFactory.createProduct("小米电脑").getName();
SimpleFactory.createProduct("苹果手机").getName();
}
}
可以看出简单工厂模式的优点是简单,对于产品的创建其实就是一个 switch 方法,不过这显然就违背了开闭原则(对于扩展开放,对于修改关闭)。因为要添加新的产品,就需要修改这个 switch 方法,添加新 case ,这违背了开闭原则中"对修改关闭"的理念。
因此这就引出了工厂方法模式。
工厂方法模式(Factory Method)
工厂方法模式定义了一个工厂接口,对于每个产品,都会有一个工厂接口的实现类来负责创建。这样就避免了简单工厂模式的扩展问题:
java
// 工厂方法模式的工厂接口
interface Factory {
Product createProduct();
}
// 小米电脑工厂
class XiaomiComputerFactory implements Factory {
@Override
public Product createProduct() { return new XiaomiComputer(); }
}
// 苹果手机工厂
class ApplePhoneFactory implements Factory {
@Override
public Product createProduct() { return new ApplePhone(); }
}
当产品使用者需要用到某个产品时,需要先创建对应的工厂,然后用工厂来创建对应的产品:
java
class Customer {
public static void main(String[] args) {
Factory xiaomiComputerFactory = new XiaomiComputerFactory();
Product xiaomiComputer = xiaomiComputerFactory.createProduct();
xiaomiComputer.getName();
Factory applePhoneFactory = new ApplePhoneFactory();
Product applePhone = applePhoneFactory.createProduct();
applePhone.getName();
}
}
从代码里可见,工厂方法模式在增加新产品时无需修改现有工厂,只需要增加一个新的工厂类而已,已有工厂无需修改,符合开闭原则。 不过它也带来了一个缺点:类数量增多,每增加一种产品就需要增加一个工厂类。
这就引出了工厂模式的最终形态------可以生产"产品家族"的抽象工厂模式。
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)是工厂模式的进一步升级,用来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
简单的说,工厂方法中,每一个工厂只能创建一个产品,而在抽象工厂中,每个工厂能创建一系列相关的产品。
为了演示抽象工厂模式,我们新增小米手机和苹果电脑产品:
java
class XiaomiPhone implements Product {
@Override
public void getName() {
System.out.println("小米手机");
}
}
class AppleComputer implements Product {
@Override
public void getName() {
System.out.println("苹果电脑");
}
}
由于每个工厂可以生产多个产品,因此需要更改工厂接口的定义和实现:
java
// 抽象工厂模式的工厂接口
interface AbstractFactory {
Product createPhone();
Product createComputer();
}
class XiaomiFactory implements AbstractFactory {
@Override
public Product createPhone() { return new XiaomiPhone(); }
@Override
public Product createComputer() { return new XiaomiComputer(); }
}
class AppleFactory implements AbstractFactory {
@Override
public Product createPhone() { return new ApplePhone(); }
@Override
public Product createComputer() { return new AppleComputer(); }
}
这里的工厂接口 AbstractFactory 只返回 Product 类型,有些时候抽象工厂接口针对不同的产品返回不同的接口类型,不过这并不是工厂模式的要求。抽象工厂模式要求产品使用方依赖抽象,而不是具体产品类,接口设计可以根据实际业务灵活选择,不必强制拆分。可以返回统一接口,也可以返回不同的产品接口,选择哪种方式取决于业务需求和产品操作差异。
这里,产品使用方可以使用如下代码使用工厂创建需要的产品:
java
class Customer {
public static void main(String[] args) {
AbstractFactory xiaomiFactory = new XiaomiFactory();
Product xiaomiPhone = xiaomiFactory.createPhone();
xiaomiPhone.getName();
AbstractFactory appleFactory = new AppleFactory();
Product applePhone = appleFactory.createPhone();
applePhone.getName();
}
}
从以上例子可以看出抽象工厂的特点:一个工厂创建一系列产品,且增加一个新的工厂比较容易(例如这里增加一个魅族工厂),但如果产品族中新增了一个产品类型,那所有的工厂就都得修改代码了。
总结
- 简单工厂模式:适合产品少、变化不频繁,使用方便,但违背开闭原则。
- 工厂方法模式:适合单个产品扩展,增加新产品无需修改已有工厂,但工厂类数量会增加。
- 抽象工厂模式:适合创建一系列相关产品,保证产品族一致性,增加产品族方便,但新增产品类型时需修改所有工厂。
选择模式时,可根据产品数量、产品族关系以及扩展需求选择最合适的方案。
