简单工厂模式

定义

简单工厂模式(Simple Factory Pattern)是值一个工厂对象觉得创建出哪一种产品类的实例。
属于创建型模式,但是它不属于GOF 23种设计模式。
简单工厂使用于工厂类负责创建的对象较少的场景,并且客户端值需要传入工厂类的参数,对于如何创建对象的逻辑不需要关系。

代码示例

我们以我们生活中常见的小汽车为例,小汽车有宝马、奔驰、玛萨拉蒂等等品牌,那么我么可以定义一个小汽车的标准接口ICar:

  1. public interface ICar {
  2. // 生产汽车
  3. void create();
  4. }

创建一个宝马汽车的示例BMW:

  1. public class BMW implements ICar {
  2. @Override
  3. public void create() {
  4. System.out.println("======生产宝马汽车======");
  5. }
  6. }

客户端在调用的时候,我们一般是这样写的:

  1. public static void main(String[] args) {
  2. ICar car = new BMW();
  3. car.create();
  4. }

上面代码中,父类ICar指向了子类BMW的引用。一般我们这样写没什么问题,但是如果在业务需要扩展,需要创建更多的品牌的汽车时,那么我们的客户端依赖会变得越来越臃肿,要减弱客户端的依赖,那我们就需要将创建细节隐藏,使用一个简单工厂类来优化我们的代码。

  1. public class CarFactory {
  2. public ICar create(String name) {
  3. if ("BMW".equals(name)) {
  4. return new BMW();
  5. } else if ("benz".equals(name)) {
  6. return new Benz();
  7. }
  8. return null;
  9. }
  10. }

修改客户端调用代码:

  1. public class SimpleFactoryTest {
  2. public static void main(String[] args) {
  3. CarFactory carFactory = new CarFactory();
  4. ICar car = carFactory.create("BMW");
  5. car.create();
  6. }
  7. }

客户端调用是简单了,但是我们的工厂类违反了开闭原则,因为在有新的汽车要生产时,我们需要修改 CarFactory 中的 create 方法。我们可以用反射技术,来对工厂类进行优化:

  1. public class CarFactory {
  2. public ICar create(Class clazz) {
  3. try {
  4. if (clazz != null) {
  5. return (ICar) clazz.newInstance();
  6. }
  7. }catch (Exception e){
  8. e.printStackTrace();
  9. }
  10. return null;
  11. }
  12. }

这时候,我们调用时只需要传入 Class 对象即可,这样既避免了在客户端调用时传错参数,也可以避免工厂类的修改。

工厂方法模式

定义

工厂方法模式(Fatory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。
工厂方法模式主要解决产品扩展的问题,在简单工厂中,随着产品链的丰富,如果每个汽车的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将职能继续拆分,专人干专事。 宝马汽车有宝马工厂创建,奔驰汽车由奔驰工厂创建,这样无论汽车的生产有怎样特殊的需求,都不影响其他汽车的生产。

代码示例

我们先对工厂做一个顶层抽象:

  1. public interface ICarFactory {
  2. ICar create();
  3. }

在分别创建子工厂,BMWFactory和BenzFactory:

  1. public class BMWFactory implements ICarFactory {
  2. @Override
  3. public ICar create() {
  4. return new BMW();
  5. }
  6. }
  1. public class BenzFactory implements ICarFactory {
  2. @Override
  3. public ICar create() {
  4. return new Benz();
  5. }
  6. }

客户端调用如下:

  1. public class FactoryMethodTest {
  2. public static void main(String[] args) {
  3. ICarFactory factory = new BMWFactory();
  4. ICar bmw = factory.create();
  5. bmw.create();
  6. ICarFactory factory2 = new BenzFactory();
  7. ICar benz = factory2.create();
  8. benz.create();
  9. }
  10. }

使用场景

工厂方法使用于以下场景:

  1. 创建对象需要大量的重复代码
  2. 客户端不依赖于产品类实例如何被创建、实现等细节
  3. 一个类通过其子类来指定创建的对象。

    缺点

    虽然工厂方法简单,清晰,但是当需要创建的产品过多时会导致类爆炸。要解决类爆炸的问题,就需要用到抽象工厂模式。

    抽象工厂模式

    定义

    抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
    在讲解抽象工厂模式之前,我们需要先了解两个概念:产品族和产品等级结构。
    产品族:所谓的产品族即是同一个厂家生产的多个产品。
    产品等级结构:产品等级结构即有多个厂家可以生成相同的产品。
    比如工厂A能够生产 A、B、C三种产品,工厂B也能生产A、B、C三种产品,那么A、B、C就表示一个产品族,工厂A 生产 A 和工厂B生产的A就表示一个产品等级结构。

    代码示例

    我们还是以汽车为例,一个汽车的组成是有发动机、车身、变速箱等等部件组成。我们先来创建一个ICarFactory的工厂接口:

    1. public interface ICarFactory {
    2. ICarBody createBody();
    3. IEngine createEngine();
    4. IGearbox createGearbox();
    5. }

    然后创建需要使用到的产品接口

    1. public interface ICarBody {
    2. void create();
    3. }
    1. public interface IEngine {
    2. void create();
    3. }

    ```java public interface IGearbox { void create(); }

  1. 这些产品的实现:
  2. ```java
  3. public class BMWBody implements ICarBody {
  4. @Override
  5. public void create() {
  6. System.out.println("生产bmw车身");
  7. }
  8. }
  1. public class BMWEngine implements IEngine {
  2. @Override
  3. public void create() {
  4. System.out.println("生产bmw 引擎");
  5. }
  6. }
  1. public class BMWGearbox implements IGearbox {
  2. @Override
  3. public void create() {
  4. System.out.println("生产bmw变速箱");
  5. }
  6. }

产品族工厂:

  1. public class BmwFactory implements ICarFactory {
  2. @Override
  3. public ICarBody createBody() {
  4. return new BMWBody();
  5. }
  6. @Override
  7. public IEngine createEngine() {
  8. return new BMWEngine();
  9. }
  10. @Override
  11. public IGearbox createGearbox() {
  12. return new BMWGearbox();
  13. }
  14. }

测试:

  1. public class AbstractFactoryTest {
  2. public static void main(String[] args) {
  3. ICarFactory carFactory = new BmwFactory();
  4. carFactory.createBody().create();
  5. carFactory.createEngine().create();
  6. carFactory.createGearbox().create();
  7. }
  8. }

其它产品族的工厂和产品定义类似。

缺点

抽象工厂虽然能一定程度上解决类爆炸的问题,但是很显然它不符合开闭原则。这是因为我们在产品族中加入一个产品时,从抽象工厂到具体实现都需要修改。因此抽象工厂也是优缺点点。
1、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口 。
2、增加了系统的抽象性和理解难度 。