学习不用那么功利,二师兄带你一起轻松读源码~
在上篇文章中,我们学习了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()); } }
客户端可根据需要,创建不同的工程子类,然后通过具体的工厂子类实现具体的产品创建。关于工厂方法模式的实现,建议对照参考简单工厂模式,这样更方便理解和学习。
工厂方法模式的优缺点
工厂方法模式对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
优点:
- 客户端只需知道具体工厂就可得到所要的产品,无须知道产品的具体创建过程;
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类;
- 符合开闭原则、符合单一职责原则、解决类简单工厂模式无法继承等级结构问题。
缺点:
- 类数量增多,新增新产品时还需要新增对应的工厂实现类;
- 增加了系统的抽象性和理解难度;
- 抽象产品只能生产一种产品,如果换一个产品的话,还是需要修改产品类的。此弊端可使用抽象工厂模式解决。
工厂方法模式的应用场景
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名;
- 创建对象的任务由多个具体工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌;
小结
就工厂模式本身而言并不难,但我们在学习设计模式时最头痛的事就是学完就忘。如果像本文这样,深刻理解了设计模式设计的初衷、使用场景以及进化历程,便更有利于记忆。本文的重点便是进行这方面思维的引导,你学到了吗?