现实生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链代工厂(抽象工厂,富士康)。我们的项目代码同样是由简到繁一步一步迭代而来的,但对于调用者来说,却越来越简单。
在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。
注意:上述复杂对象指的是类的构造函数参数过多等对类的构造有影响的情况,因为类的构造过于复杂,如果直接在其他业务类内使用,则两者的耦合过重,后续业务更改,就需要在任何引用该类的源代码内进行更改,光是查找所有依赖就很消耗时间了,更别说要一个一个修改了。
按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式
、工厂方法模式
和抽象工厂模式
。
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。
简单工厂并未被纳入5种创建型模式,这里也一并介绍了。
简单工厂模式的定义和特点
如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
在简单工厂模式中创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
缺点:
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,违背了开闭原则,在产品类型较多时,可能造成逻辑过于复杂
使用场景: 对于产品种类相对较少的情况,考虑使用简单工厂模式。明确地计划不同条件下创建不同实例
使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品
简单工厂模式的结构与实现
简单工厂模式的主要角色如下:
- 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
- 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
- 具体产品(ConcreteProduct):是简单工厂模式的创建目标。
其结构图如下图所示:
实现
步骤1:新增抽象产品
/**
* 步骤1:新增抽象产品
*/
interface Product {
void show();
}
步骤 2:创建两个产品
/**
* 步骤 2:创建两个产品
*/
class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1显示...");
}
}
class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2显示...");
}
}
步骤 3:创建简单工厂,根据参数来得到具体的产品
/**
* 步骤 3:创建简单工厂,根据参数来得到具体的产品
*/
class SimpleFactory {
public Product makeProduct(int type) {
if (1 == type) {
return new ConcreteProduct1();
} else if (2 == type) {
return new ConcreteProduct2();
}
return null;
}
}
调用
package cn.datang.shejims.simplefactory;
public class SimpleFactoryDemo {
public static void main(String[] args) {
SimpleFactory factory = new SimpleFactory();
Product product1 = factory.makeProduct(1);
product1.show();
Product product2 = factory.makeProduct(2);
product2.show();
}
}
工厂方法模式的定义和特点
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式让实例化推迟到子类。
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌
工厂方法模式的结构和实现
工厂方法模式的主要角色如下。
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
其结构图如图 下图 所示:
实现
步骤 1:创建抽象产品
/**
* 步骤 1:创建抽象产品
*/
interface Product {
void show();
}
步骤 2:创建两个产品
/**
* 步骤 2:创建两个产品
*/
class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1显示...");
}
}
class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2显示...");
}
}
步骤 3:创建抽象工厂
/**
* 步骤 3:创建抽象工厂
*/
interface AbstractFactory {
Product newProduct();
}
步骤 4:创建两个具体工厂
/**
* 步骤 4:创建两个具体工厂
*/
class ConcreteFactory1 implements AbstractFactory {
@Override
public Product newProduct() {
System.out.println("具体工厂1生成-->具体产品1...");
return new ConcreteProduct1();
}
}
class ConcreteFactory2 implements AbstractFactory {
@Override
public Product newProduct() {
System.out.println("具体工厂2生成-->具体产品2...");
return new ConcreteProduct2();
}
}
调用
package cn.datang.shejims.factorymethod;
public class FactoryMethodDemo {
public static void main(String[] args) {
AbstractFactory abstractFactory1 = new ConcreteFactory1();
Product product1 = abstractFactory1.newProduct();
product1.show();
AbstractFactory abstractFactory2 = new ConcreteFactory2();
Product product2 = abstractFactory2.newProduct();
product2.show();
}
}