03 设计模式之工厂模式

Posted 陈皮的JavaLib

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了03 设计模式之工厂模式相关的知识,希望对你有一定的参考价值。

我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复【资料】,即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板。

1 背景


在 Java 中,提倡面向接口编程,接口可以定义约束实现类的行为,外部调用通过接口进行调用,达到了封装隔离的效果,外部不知道内部的具实现。而且使用接口编程,提高了可维护性和可扩展性。

package com.chenpi.simplefactory;

/**
 * @Description
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class ChenPiMain {

  public static void main(String[] args) {
    PayService payService = new AliPayService();
    payService.pay();
  }

}

interface PayService {

  void pay();
}

class AliPayService implements PayService {

  @Override
  public void pay() {
    System.out.println("使用支付宝支付...");
  }
}

以上代码其实有问题的,本来是要面向接口编程,但是客户端却知道了接口实现类,违背了封装隔离原则。那就不要让客户端去创建具体实现类,那接口实现类又该如何获取呢?


2 工厂模式


工厂模式可以解决以上问题。工厂模式属于创建型模式,它提供了一个创建对象实例的功能,而不关心其具体的实现。

工厂模式主要有工厂方法模式,抽象工厂模式两类。


2.1 工厂方法(Factory Method)


定义一个用于创建对象的接口,接口实现类决定创建哪一个类的实例,工厂方法使一个类的实例化延迟到接口的实现子类上。


工厂方法模式的结构图如下:

  • Product:定义工厂方法所创建的对象的接口。
  • ConcreteProduct:Product 接口的实现类。
  • XXFactory:工厂抽象类,里面定义一个抽象方法,返回被创建的对象的接口。
  • ConcreteXXFactory:工厂抽象方法的实现类,负责工厂方法的实例创建。


还是以开头的例子演示,工厂方法创建的实例一般都有共同的父亲,所以需要定义一个接口。

package com.chenpi.factorymethod;

/**
 * @Description 被创建实例的接口
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public interface PayService {

  void pay();
}

再定义接口的实现类,也就是工厂实际创建的对象。

package com.chenpi.factorymethod;

/**
 * @Description 被创建实例接口的实现类
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class AliPayService implements PayService {

  @Override
  public void pay() {
    System.out.println("使用支付宝支付...");
  }
}

工厂抽象类,定义约束了需要创建的对象接口,具体实现由子类负责。工厂类的名称一般为模块名称+Factory

package com.chenpi.factorymethod;

/**
 * @Description 工厂抽象类
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public abstract class PayServiceFactory {

  public abstract PayService getPayService();
}

工厂接口的实现类,负责创建实际需要的对象实例。

package com.chenpi.factorymethod;

/**
 * @Description 工厂接口实现类
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class AliPayServiceFactory extends PayServiceFactory {

  @Override
  public PayService getPayService() {
    return new AliPayService();
  }
}

客户端使用工厂获取对象,进行使用。

package com.chenpi.factorymethod;

/**
 * @Description
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class ChenPiClient {

  public static void main(String[] args) {
    PayServiceFactory factory = new AliPayServiceFactory();
    PayService payService = factory.getPayService();
    payService.pay();
  }
}

// 输出结果
使用支付宝支付...

如果此时又要新增一个支付方式,例如微信支付,那么只需要新增一个微信支付相关的业务类,以及对象的工厂实现类即可。

package com.chenpi.factorymethod;

/**
 * @Description 被创建实例接口的实现类
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class WeChatPayService implements PayService {

  @Override
  public void pay() {
    System.out.println("使用微信支付...");
  }
}

package com.chenpi.factorymethod;

/**
 * @Description 工厂接口实现类
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class WeChatPayServiceFactory extends PayServiceFactory {

  @Override
  public PayService getPayService() {
    return new WeChatPayService();
  }
}

客户端只需要更好具体的工厂实现类即可。

package com.chenpi.factorymethod;

/**
 * @Description
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class ChenPiClient {

  public static void main(String[] args) {
    PayServiceFactory factory = new WeChatPayServiceFactory();
    PayService payService = factory.getPayService();
    payService.pay();
  }
}

// 输出结果
使用微信支付...

当然这些结构不一定都是定死的,设计模式表达的是一种思想,思路,具体的落地方案都是得根据实际情况而定的,比如工厂方法模式不一定要定义工厂接口以及多个实现类,也可以直接定义一个工厂具体类,根据客户端传入的参数或者读取其他数据(例如配置文件,数据库等)选择创建具体的实例即可。

package com.chenpi.factorymethod;

/**
 * @Description 工厂方法
 * @Author 陈皮
 * @Date 2021/8/1
 * @Version 1.0
 */
public class OnlinePayServiceFactory {

  public PayService getPayService(String type) {
    if ("AliPay".equals(type)) {
      return new AliPayService();
    } else if ("WeChatPay".equals(type)) {
      return new WeChatPayService();
    }
    return null;
  }
}

2.2 抽象工厂(Abstract Factory)


工厂方法一般是创建单个类的实例,或者没有内在联系的类的实例。而且抽象工厂一般是创建有关联,或者相互依赖的类的实例,可以理解为生产产品簇的工厂。


抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的实现类。

  • AbstractFactory:抽象工厂,定义约束创建一系列产品对象的操作接口。
  • ConcreteFactory:抽象工厂的具体实现类,负责一系列有相互关系的类的对象的创建。
  • AbstractProduct:定义一系列产品对象的接口。
  • ConcreteProduct:产品接口的具体实现类。


举个例子,假如你要开个电脑组装公司,业务是帮一些电脑小白组装电脑,为简单方便讲解,我们假设组装一个电脑只需要 CPU,显示屏以及主板。那组装总公司(抽象工厂)定义约束了组装一个电脑需要哪些组件接口(一系列对象接口),但是具体牌子的电脑组件由不同的子公司(接口实现类)来实现,而且这些组件是有互相依赖关系的。总而言之,抽象工厂就是起到一个定义约束的作用,实现子类必须要接口定义来创建一系列对象。


首先定义一个抽象工厂接口,在里面定义约束创建一系列电脑组件的接口。

package com.chenpi.abstractfactory;

/**
 * @Description 抽象工厂
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public interface AbstractFactory {

  CPU getCPU();

  Mainboard getMainboard();
}

再定义抽象工厂接口的实现类,也就是具体的组装电脑方案实现。

package com.chenpi.abstractfactory;

/**
 * @Description 抽象工厂实现类A
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteFactoryA implements AbstractFactory {

  @Override
  public CPU getCPU() {
    return new ConcreteCPUA();
  }

  @Override
  public Mainboard getMainboard() {
    return new ConcreteMainboardA();
  }
}

package com.chenpi.abstractfactory;

/**
 * @Description 抽象工厂实现类B
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteFactoryB implements AbstractFactory {

  @Override
  public CPU getCPU() {
    return new ConcreteCPUB();
  }

  @Override
  public Mainboard getMainboard() {
    return new ConcreteMainboardB();
  }
}

CPU 产品接口定义,以及 CPU 具体实现类定义。

package com.chenpi.abstractfactory;

/**
 * @Description 抽象CPU接口
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public interface CPU {

}

package com.chenpi.abstractfactory;

/**
 * @Description 具体品牌A的CPU
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteCPUA implements CPU {

}

package com.chenpi.abstractfactory;

/**
 * @Description 具体品牌B的CPU
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteCPUB implements CPU {

}

主板产品接口定义,以及主板接口的具体实现类定义。

package com.chenpi.abstractfactory;

/**
 * @Description 抽象主板接口
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public interface Mainboard {

}

package com.chenpi.abstractfactory;

/**
 * @Description 品牌A的主板
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteMainboardA implements Mainboard {

}

package com.chenpi.abstractfactory;

/**
 * @Description 品牌B的主板
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class ConcreteMainboardB implements Mainboard {

}

编写客户端,进行验证,假设选择方案 A 进行验证。

package com.chenpi.abstractfactory;

/**
 * @Description
 * @Author 陈皮
 * @Date 2021/8/3
 * @Version 1.0
 */
public class Client {

  public static void main(String[] args) {
    AbstractFactory factory = new ConcreteFactoryA();
    CPU cpu = factory.getCPU();
    Mainboard mainboard = factory.getMainboard();

    System.out.println("CPU:" + cpu);
    System.out.println("Mainboard:" + mainboard);
  }
}

// 输出结果
CPU:com.chenpi.abstractfactory.ConcreteCPUA@4554617c
Mainboard:com.chenpi.abstractfactory.ConcreteMainboardA@74a14482

通过抽象工厂模式,确保了一个具体的工厂只生产有互相关联,互相依赖的产品簇,不会出现混乱搭配的情况。



本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

以上是关于03 设计模式之工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

03 设计模式之工厂模式

设计模式之单例模式

从零玩转设计模式之抽象工厂设计模式-chouxiangshejimoshi

Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---工厂模式之简单工厂

设计模式之简单工厂模式

设计模式之简单工厂模式