1.前言
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
- 举个例子来说,就是一个电脑生产厂,它可以生产型号A、型号B和型号C。
工厂模式的三种实现方式
- 简单工厂模式:通过传入相应的类型来返回对应的产品类,这种方式比较单一,可拓展性比较差
- 工厂方法模式:通过具体的工厂类实现相应的方法返回相应的产品类,这种方式可拓展性比较强
- 抽象工厂模式:基于上述两种模式的拓展,且⽀持细化产品
应用场景
- 解耦合:把对象的创建和使用的过程分开。就是Class A 想调用 Class B ,那么A只是调用B的方法,而至于B的实例化,就交给工厂类。
- 复用代码,降低代码重复:如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。
2.简单工厂模式
核心组成
- Factory:工厂类,简单工厂模式的核心,包含了所有创建实例的内部逻辑
- IProduct:抽象产品类,简单工厂模式创建所有产品类的父类,描述所有实例所共有的公共接口
- Product:具体产品类,是简单工厂创建的目标
实现
实现分为三步:
- 创建抽象产品类,具体的业务逻辑由具体产品类实现
- 创建具体产品类,继承抽象产品类,事项具体的业务
- 创建工厂类,实现获取产品类的方法,方法会根据传入的参数去生成具体的产品类
抽象产品类
public interface ICalculation {
int getResult(int num1, int num2);
}
具体产品类
public class CalculationSubtract implements ICalculation {
@Override
public int getResult(int num1, int num2) {
return num1 - num2;
}
}
public class CalculationMultiply implements ICalculation {
@Override
public int getResult(int num1, int num2) {
return num1 * num2;
}
}
public class CalculationAdd implements ICalculation {
@Override
public int getResult(int num1, int num2) {
return num1 + num2;
}
}
工厂类
public class SimpleCalculationFactory {
public ICalculation createCalculation(String operation){
switch (operation){
case "+":
return new CalculationAdd();
case "-":
return new CalculationSubtract();
case "*":
return new CalculationMultiply();
default:
return null;
}
}
}
测试类
public class SimpleCalculationTest {
public static void main(String[] args) {
SimpleCalculationFactory simpleCalculationFactory = new SimpleCalculationFactory();
ICalculation calculation = simpleCalculationFactory.createCalculation("+");
int result = calculation.getResult(1, 2);
System.out.println(result);
}
}
UML类图
优点与缺点
优点
- 将对象的创建和对象本身的业务处理分离可以降低系统的耦合度,使两者修改起来比较容易。
缺点
- 工厂类的职责过重,增加新的产品就需要修改工厂类的逻辑判断,这违反了开闭原则(软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭)。
3.工厂方法模式
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法把实例化推迟到子类。这样的好处是再添加新的对象的时候,就不用再改代码了,代码的可扩展性强了。要做的就是:子类工厂继承或实现抽象的工厂,写一个新的创建类的工厂,然后再在客户端调用即可,不需要修改原来的代码。
核心组成
- IProduct:抽象产品接口,描述所有实例所共有的公共接⼝
- Product:具体产品类,实现抽象产品类的接⼝,⼯⼚类创建对象,如果有多个需要定义多个
- IFactory:抽象⼯⼚接口,描述具体⼯⼚的公共接⼝
- Factory:具体⼯⼚类,实现创建产品类对象,实现抽 象⼯⼚类的接⼝,如果有多个需要定义多个
实现
实现分为四步:
- 创建抽象产品类,具体的业务逻辑由具体产品类实现
- 创建具体产品类,继承抽象产品类,事项具体的业务
- 创建抽象工厂类,描述具体工厂
- 创建工厂类,实现获取产品类的方法,方法会根据传入的参数去生成具体的产品类
这里抽象产品类以及具体产品类与简单工厂中的实现相同,这里就不再做展示。
我们直接展示抽象工厂类和具体工厂类。
抽象工厂类
public interface IFactory {
ICalculation createCalculation();
}
具体工厂类
public class AddFactory implements IFactory{
@Override
public ICalculation createCalculation() {
return new CalculationAdd();
}
}
public class MultiplyFactory implements IFactory{
@Override
public ICalculation createCalculation() {
return new CalculationMultiply();
}
}
public class SubtractFactory implements IFactory{
@Override
public ICalculation createCalculation() {
return new CalculationSubtract();
}
}
测试代码
public class FactoryMethodTest {
public static void main(String[] args) {
IFactory addFactory = new AddFactory();
ICalculation calculation = addFactory.createCalculation();
int result = calculation.getResult(1, 2);
System.out.println(result);
}
}
UML类图
优点与缺点
优点
- 符合开闭原则,增加⼀个产品类,只需要实现其他具体的产品类和具体的⼯⼚类;
- 符合单⼀职责原则,每个⼯⼚只负责⽣产对应的产品;
- 使⽤者只需要知道产品的抽象类,⽆须关⼼其他实现类,满⾜迪⽶特法则、依赖倒置原则和⾥⽒替换原则;
- 迪⽶特法则:最少知道原则,实体应当尽量少地与 其他实体之间发⽣相互作⽤;
- 依赖倒置原则:针对接⼝编程,依赖于抽象⽽不依赖于具体;
- ⾥⽒替换原则:俗称LSP,任何基类可以出现的地⽅,⼦类⼀定可以出现, 对实现抽象化的具体步骤的规范;
缺点
- 增加⼀个产品,需要实现对应的具体⼯⼚类和具体产品类;
- 每个产品需要有对应的具体⼯⼚和具体产品类;
4.抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体定。抽象工厂允许客户使用抽象确有工厂创建一组相关的产品,而不需要(或关心)实际产出的具体产品是什么。这样一样,客户就从具体的产品中被解耦。
在前面的工厂方法模式中,考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机。工厂方法模式只考虑生产同等级(同种类被称为同等级)的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调。而抽象工厂模式就考虑了多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,如图所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
核心组成
- IFactory:抽象工厂类,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口。
- ConcreteFactory:具体工厂类,用于生产不同产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象。
- IProduct:抽象产品类,这是一个产品家族,每一个具体工厂都能够生产一整组产品。
- Product:具体产品类
实现
这里拿Haier和TCL的电器作为例子来讲解抽象工厂模式。
抽象工厂类
public interface IFactory {
IAirCondition createAirCondition();
ITelevision createTelevision();
}
具体工厂类
public class HaierFactory implements IFactory{
@Override
public IAirCondition createAirCondition() {
return new HaierAirCondition();
}
@Override
public ITelevision createTelevision() {
return new HaierTelevision();
}
}
public class TCLFactory implements IFactory{
@Override
public IAirCondition createAirCondition() {
return new TCLAirCondition();
}
@Override
public ITelevision createTelevision() {
return new TCLTelevision();
}
}
抽象产品类
public interface ITelevision {
void show();
}
public interface IAirCondition {
void airConditioning();
}
具体产品类
public class HaierTelevision implements ITelevision{
@Override
public void show() {
System.out.println("Haier电视启动了,显示效果偏暖......");
}
}
public class HaierAirCondition implements IAirCondition{
@Override
public void airConditioning() {
System.out.println("Haier空调启动了,温度开始变化......");
}
}
public class TCLAirCondition implements IAirCondition{
@Override
public void airConditioning() {
System.out.println("TCL空调启动了,温度开始变化......");
}
}
public class TCLTelevision implements ITelevision{
@Override
public void show() {
System.out.println("TCL电视启动了,显示效果偏冷......");
}
}
UML类图
优点与缺点
优点
- 当⼀个产品族中的多个对象被设计成⼀起⼯作时,它能 保证使⽤⽅始终只使⽤同⼀个产品族中的对象
- 产品等级结构扩展容易,如果需要增加多⼀个产品等级,只需要增加新的⼯⼚类和产品类即可
缺点
- 产品族扩展困难,要增加⼀个系列的某⼀产品,既要在 抽象的⼯⼚和抽象产品⾥修改代码,不是很符合开闭原 则
- 增加了系统的抽象性和理解难度