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

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

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


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


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


工厂方法模式

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


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


工厂方法模式简介

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


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


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


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


工厂方法模式结构图

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


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

image.png上图中被虚线框起来的部分便是变化的部分,第一个变化是工厂类被抽象化了,提供了一个抽象的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());
    }
}

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


工厂方法模式的优缺点

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


优点:


客户端只需知道具体工厂就可得到所要的产品,无须知道产品的具体创建过程;

灵活性增强,对于新产品的创建,只需多写一个相应的工厂类;

符合开闭原则、符合单一职责原则、解决类简单工厂模式无法继承等级结构问题。

缺点:


类数量增多,新增新产品时还需要新增对应的工厂实现类;

增加了系统的抽象性和理解难度;

抽象产品只能生产一种产品,如果换一个产品的话,还是需要修改产品类的。此弊端可使用抽象工厂模式解决。

工厂方法模式的应用场景

应用场景:


客户只知道创建产品的工厂名,而不知道具体的产品名;

创建对象的任务由多个具体工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

客户不关心创建产品的细节,只关心产品的品牌;

小结

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



目录
相关文章
|
安全 Java Spring
SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六)
SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六)
187 0
|
3月前
|
存储 NoSQL Dubbo
Java主流分布式解决方案多场景设计与实战
本文介绍了Java领域的主流分布式技术,涵盖分布式服务框架(如Dubbo、Spring Cloud)、分布式数据存储(如Redis、MongoDB)、分布式锁(如ZooKeeper、Redisson)及分布式事务(如Seata、Hmily),并通过电商项目案例分析了这些技术在实际开发中的应用,帮助开发者应对高并发与大数据挑战。
122 0
|
3月前
|
人工智能 安全 Java
Spring Boot 中使用 Function 和异步线程池处理列表拆分任务并汇总结果
在Java开发中,处理大规模数据时常常需要将列表拆分为多个子列表进行异步处理并汇总结果。本文介绍如何在Spring Boot中使用Function和异步线程池实现高效且可维护的代码,涵盖结果封装、线程池配置、列表拆分处理及结果汇总等关键步骤。
136 0
|
5月前
|
SQL 关系型数据库 MySQL
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
|
5月前
|
Arthas 监控 Java
Arthas dashboard(当前系统的实时数据面板)
Arthas dashboard(当前系统的实时数据面板)
259 12
|
5月前
|
缓存 Java Nacos
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
|
3月前
|
消息中间件 存储 缓存
超全面Java中的队列(Queue)
Java中的`Queue`接口位于`java.util`包,继承自`Collection`,用于存储待处理的元素,通常遵循FIFO原则。它包含`add`、`offer`、`poll`等方法,支持多种实现类,如`LinkedList`、`PriorityQueue`、`ArrayDeque`、`ConcurrentLinkedQueue`及`BlockingQueue`系列。
339 0
|
6月前
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
11月前
|
存储 缓存 NoSQL
京东面试:亿级黑名单 如何设计?亿级查重 呢?(答案含:布隆过滤器、布谷鸟过滤器)
尼恩,40岁的老架构师,近期在读者交流群中分享了几个大厂面试题及其解决方案。这些问题包括亿级数据查重、黑名单存储、电话号码判断、安全网址判断等。尼恩给出了三种解决方案:使用BitMap位图、BloomFilter布隆过滤器和CuckooFilter布谷鸟过滤器。这些方法不仅高效,还能显著提升面试表现。尼恩还建议大家系统化学习,刷题《尼恩Java面试宝典PDF》,并提供简历修改和面试辅导,帮助大家实现“offer自由”。更多技术资料和PDF可在公众号【技术自由圈】获取。
|
11月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
178 3