工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory)(不是设计模式)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

简单工厂其实不是一个标准的的设计模式。GOF 23 种设计模式中只有「工厂方法模式」与「抽象工厂模式」。简单工厂模式可以看为工厂方法模式的一种特例,为了统一整理学习,就都归为工厂模式。
这三种工厂模式在设计模式的分类中都属于创建型模式,三种模式从上到下逐步抽象。

一、简单工场模式

简单工厂模式,真是因为简单才被叫做简单工厂模式的。
简单工厂模式包含 3 个角色(要素):

  • Factory:即工厂类, 简单工厂模式的核心部分,负责实现创建所有产品的内部逻辑;工厂类可以被外界直接调用,创建所需对象
  • Product:抽象类产品, 它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象
  • ConcreteProduct:具体产品, 它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。它要实现抽象产品中声明的抽象方法
    ```java // 计算类的基类 @Setter @Getter public abstract class Operation { private double value1 = 0; private double value2 = 0; protected abstract double getResule(); }

//加法 public class OperationAdd extends Operation { @Override protected double getResule() { return getValue1() + getValue2(); } } //减法 public class OperationSub extends Operation { @Override protected double getResule() { return getValue1() - getValue2(); } } //乘法 public class OperationMul extends Operation { @Override protected double getResule() { return getValue1() * getValue2(); } } //除法 public class OperationDiv extends Operation { @Override protected double getResule() { if (getValue2() != 0) { return getValue1() / getValue2(); } throw new IllegalArgumentException(“除数不能为零”); } }

  1. ```java
  2. //工厂类
  3. public class OperationFactory {
  4. public static Operation createOperation(String operation) {
  5. Operation oper = null;
  6. switch (operation) {
  7. case "add":
  8. oper = new OperationAdd();
  9. break;
  10. case "sub":
  11. oper = new OperationSub();
  12. break;
  13. case "mul":
  14. oper = new OperationMul();
  15. break;
  16. case "div":
  17. oper = new OperationDiv();
  18. break;
  19. default:
  20. throw new UnsupportedOperationException("不支持该操作");
  21. }
  22. return oper;
  23. }
  24. }

有了工厂类之后,可以使用工厂创建对象:

  1. public static void main(String[] args) {
  2. Operation operationAdd = OperationFactory.createOperation("add");
  3. operationAdd.setValue1(1);
  4. operationAdd.setValue2(2)
  5. System.out.println(operationAdd.getResule());
  6. }

1.3 简单工厂模式存在的问题

当我们需要增加一种计算时,例如开平方。这个时候我们需要先定义一个类继承 Operation 类,其中实现平方的代码。除此之外我们还要修改 OperationFactory 类的代码,增加一个 case。这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。
我们举的例子是最简单的情况。而在实际应用中,很可能产品是一个多层次的树状结构。 简单工厂可能就不太适用了。

1.4 简单工厂模式总结

工厂类是整个简单工厂模式的关键。包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。
但是由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
为了解决这些缺点,就有了工厂方法模式。

二、工厂方法模式

我们常说的工厂模式,就是指「工厂方法模式」,也叫「虚拟构造器模式」或「多态工厂模式」。

2.1 定义

定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行

2.2 工厂方法模式实现方式

工厂方法模式包含 4 个角色(要素):

  • Product:抽象产品,定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口
  • ConcreteProduct:具体产品,具体的 Product 接口的实现对象
  • Factory:工厂接口,也可以叫 Creator(创建器),申明工厂方法,通常返回一个 Product 类型的实例对象
  • ConcreteFactory:工厂实现,或者叫 ConcreteCreator(创建器对象),覆盖 Factory 定义的工厂方法,返回具体的 Product 实例 ``` //工厂接口 public interface IFactory { Operation CreateOption(); }

//加法类工厂 public class AddFactory implements IFactory { public Operation CreateOption() { return new OperationAdd(); } }

//减法类工厂 public class SubFactory implements IFactory { public Operation CreateOption() { return new OperationSub(); } }

//乘法类工厂 public class MulFactory implements IFactory { public Operation CreateOption() { return new OperationMul(); } }

//除法类工厂 public class DivFactory implements IFactory { public Operation CreateOption() { return new OperationDiv(); } }

  1. 这时,我们使用计算器的时候,要为每种运算方法增加一个工厂对象

public class Client { public static void main(String[] args) { //减法 IFactory subFactory = new SubFactory(); Operation operationSub = subFactory.CreateOption(); operationSub.setValue1(22); operationSub.setValue2(20); System.out.println(“sub:”+operationSub.getResult()); //除法 IFactory Divfactory = new DivFactory(); Operation operationDiv = Divfactory.CreateOption(); operationDiv.setValue1(99); operationDiv.setValue2(33); System.out.println(“div:”+operationSub.getResult()); } } ``` 纳尼,这不是更复杂了吗,每个产品对应一个工厂,我又不是按代码量赚钱的。。。

2.3 工厂方法模式适用场景

工厂方法模式和简单工厂模式虽然都是通过工厂来创建对象,他们之间最大的不同是——工厂方法模式在设计上完全完全符合“开闭原则”。
在以下情况下可以使用工厂方法模式:

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

    使用场景

  • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

  • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
  • 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。
  • 比如 Hibernate 换数据库只需换方言和驱动就可以

    2.4 工厂方法模式总结

    工厂方法模式是简单工厂模式的进一步抽象和推广。
    由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
    在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
    优点:

  • 一个调用者想创建一个对象,只要知道其名称就可以了。

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  • 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。