学习不用那么功利,二师兄带你一起轻松读源码~

在上篇文章中,我们学习了Nacos中是如何灵活运用《简单工厂模式》的。而设计模式在面试过程中也经常会出现。当面试官问到:说说工厂模式是如何实现的?他问的工厂模式指的是什么?

这篇文章属于扩展篇的扩展,我们基于简单工厂模式,再来聊聊工厂模式。

工厂方法模式

先来回答上面的问题,如果笼统的讲工厂模式,通常包括:简单工厂/静态工厂、工厂方法模式和抽象工厂模式。上节讲了简单工厂模式,而抽象工厂模式一般应用在比较复杂的大型应用中,也不太常见。

因此,如果工厂模式只是指某一个模式的话,那么说的就是工厂方法模式。

工厂方法模式简介

工厂方法模式(Factory Method Pattern)又称工厂模式、多态工厂模式和虚拟构造器模式。

在讲简单工厂模式时,已经知道该模式存在一些缺点,比如工厂类业务逻辑过于复杂,违背了开闭原则和高内聚低耦合的原则。同时,还由于方法是静态的,还无法形成继承的层级结构。

那么,我们是否可以将工厂类进行抽象,提供一个公共的接口,而工厂类的子类负责创建具体的产品对象,这样不就达到了解耦的目标了吗?

因此,在工厂方法模式中,工厂父类定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,通过工厂子类来确定究竟应该实例化哪一个具体的产品类。

工厂方法模式结构图

在看工厂方法模式的结构图之前,先来回顾一下简单工厂模式的结构图:

简单工厂模式

我们对此结构图进行扩展,将Factory这个工厂类进行抽象化处理,于是就得到工厂方法模式:

工厂方法模式

上图中被虚线框起来的部分便是变化的部分,第一个变化是工厂类被抽象化了,提供了一个抽象的AbstractFactory。既然抽象了,必定会有具体的工厂实现类,这个实现类与产品相对照。这样,便达到了修改一个产品的创建逻辑,并不会影响到其他产品的创建,达到了解耦的效果。

下面再梳理一下工厂方法模式的核心角色:

  • 抽象产品(Product):产品的抽象类或接口,负责定义产品的特征和共性。
  • 具体产品(Concrete Product):具体的产品类。
  • 抽象工厂(AbstractFactory):产品的创建类,工厂接口。
  • 具体工厂(ConcreteFactory):具体的创建类,工厂实现。

工厂方法模式实现

这里的实例我们还以Nacos的配置服务和命名服务为例。假设配置服务和命名服务都集成自同一个NacosService,同时呢,它们的创建又通过不同的子工厂进行创建。

定义抽象产品类及其实现类:

// 抽象产品类
public interface NacosService {
   /**
    * 注册实例信息
    * @param object 实例信息,这里用Object代替
    */
   void register(Object object);
}

// 配置中心服务实现
public class ConfigService implements NacosService {
   @Override
   public void register(Object object) {
      System.out.println("配置中心实例注册成功");
   }
}

// 命名服务注册实现
public class NamingService implements NacosService {
   @Override
   public void register(Object object) {
      System.out.println("注册命名服务成功");
   }
}

定义抽象工厂类及其实现类:

// 抽象工厂类,定义统一的方法
public interface NacosFactory {
    NacosService getService();
}

// 配置服务的工厂类实现
public class ConfigNacosFactory implements NacosFactory {
    @Override
    public NacosService getService() {
        return new ConfigService();
    }
}

// 命名服务的工厂类实现
public class NamingNacosFactory implements NacosFactory {
    @Override
    public NacosService getService() {
        return new NamingService();
    }
}

客户端实现:

public class Client {

    public static void main(String[] args) {

        // 配置中心
        ConfigNacosFactory configNacosFactory = new ConfigNacosFactory();
        NacosService configService = configNacosFactory.getService();
        configService.register(new Object());

        // 注册中心
        NamingNacosFactory namingNacosFactory = new NamingNacosFactory();
        NacosService namingService = namingNacosFactory.getService();
        namingService.register(new Object());
    }
}

客户端可根据需要,创建不同的工程子类,然后通过具体的工厂子类实现具体的产品创建。关于工厂方法模式的实现,建议对照参考简单工厂模式,这样更方便理解和学习。

工厂方法模式的优缺点

工厂方法模式对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

优点:

  • 客户端只需知道具体工厂就可得到所要的产品,无须知道产品的具体创建过程;
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类;
  • 符合开闭原则、符合单一职责原则、解决类简单工厂模式无法继承等级结构问题。

缺点:

  • 类数量增多,新增新产品时还需要新增对应的工厂实现类;
  • 增加了系统的抽象性和理解难度;
  • 抽象产品只能生产一种产品,如果换一个产品的话,还是需要修改产品类的。此弊端可使用抽象工厂模式解决。

工厂方法模式的应用场景

应用场景:

  • 客户只知道创建产品的工厂名,而不知道具体的产品名;
  • 创建对象的任务由多个具体工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌;

小结

就工厂模式本身而言并不难,但我们在学习设计模式时最头痛的事就是学完就往。如果想本文这样,深刻理解了设计模式设计的初衷、使用场景以及进化历程,便更有利于记忆。本文的重点便是进行这方面思维的引导,你学到了吗?

如果文章内容有问题或想技术讨论请联系我(微信:zhuan2quan,备注Nacos),如果觉得写的还不错,值得一起学习,那就关注一下吧。

博主简介:《SpringBoot技术内幕》技术图书作者,酷爱钻研技术,写技术干货文章。

公众号:「程序新视界」,博主的公众号,欢迎关注~

技术交流:请联系博主微信号:zhuan2quan



《跟二师兄学Nacos吧》EXT-02篇 面试官问工厂模式,你理解的对吗?插图2

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://choupangxia.com/2021/07/20/ext-02-factory-method-pattern/