《跟二师兄学Nacos吧》EXT-01篇 看看Nacos是怎么活学活用简单工厂模式的!

简介: 《跟二师兄学Nacos吧》EXT-01篇 看看Nacos是怎么活学活用简单工厂模式的!

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


番外篇简介

Nacos源码分析系列文章,在开篇已经提到过,写作的目标有两个:第一,能够系统的学习Nacos知识;第二,能够基于Nacos学到涉及到的知识点或面。


为了方便大家学习,相对应的文章标题会有所区别,Nacos原理部分命名按照正常编号进行。而番外篇,也就是技术点的讲解则会在文章编号上添加“EXT-”的前缀。这样,如果大家只想学习Nacos原理知识,则可跳过EXT前缀的文章。


这篇文章我们来看看Nacos Client中对工厂模式的使用。这里分两个步骤来了解,首先看看标准的工厂模式是什么样子的,然后再对比一下Nacos中的实现与标准实现有什么区别。


工厂模式概述

在23种设计模式当中,工厂模式包含两种:工厂方法模式和抽象工厂模式。它们都属于创建型模式,而还有一种简单工厂模式,虽然经常被用到,但可能是过于简单,未被纳入23种设计模式当中。


简单工厂模式

下面先介绍一下,简单工厂模式,并对Nacos中的使用进行对比,并思考为什么会这样设计。


简单工厂模式简介

简单工厂模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象根据不同的参数类型返回不同实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。


对于简单工厂模式,要解决的问题便是封装实例创建的过程。需要什么类,只需传入一个对应的参数,就可以获得所需的对象,调用者无需知道实例的创建过程。被创建的实例通常都具有共同的父类。


简单工厂模式的结构

UML图展示如下:



image.png简单工厂通常包括三部分:


Factory(工厂):核心部分,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象;

AbstractProduct(抽象产品类):工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象;

ConcreteProduct(具体产品):简单工厂模式的创建目标,实现了抽象产品类,所有被创建的对象都是某个具体类的实例;

其中抽象产品类可以是接口,也可以说抽象类。


简单工厂模式的实现

这里假设Nacos的配置中心服务和命名服务都继承自统一的NacosService,同时都需要提供一个注册方法。


抽象产品类定义如下:


public interface NacosService {

  /**

   * 注册实例信息

   * @param object 实例信息,这里用Object代替

   */

  void register(Object object);

}

1

2

3

4

5

6

7

命名服务NamingService的具体实现:


public class NamingService implements NacosService {


  @Override

  public void register(Object object) {

     System.out.println("注册命名服务成功");

  }

}

1

2

3

4

5

6

7

配置服务ConfigService的具体实现:


public class ConfigService implements NacosService {


  @Override

  public void register(Object object) {

     System.out.println("配置中心实例注册成功");

  }

}

1

2

3

4

5

6

7

提供一个工厂类NacosFactory:


public class NacosFactory {


  public static NacosService getService(String name) {

     if ("naming".equals(name)) {

        return new NamingService();

     } else {

        return new ConfigService();

     }

  }

}

1

2

3

4

5

6

7

8

9

10

其中根据传入的参数,生成不同类型的NacosService具体实现。


此时,客户端就可以直接调用该工厂:


public class Client {


  public static void main(String[] args) {


     NacosService nacosService = NacosFactory.getService("naming");

     nacosService.register(new Object());

  }

}

1

2

3

4

5

6

7

8

可以看出,此时客户端并不需要关注NacosService的具体实现类是如何被创建的,只需要通过NacosFactory来创建即可。这样,就把比较复杂的创建过程封装在了工厂类中。


简单工厂模式的优缺点

简单工厂模式的优点:


工厂类可包含必要的逻辑判断,可决定不同参数创建不同产品的实例。实现了创建职责的分离;

客户端无需知道所创建具体产品的类名,只需知道参数即可;

通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性;

简单工厂模式的缺点:


工厂类集成了产品创建逻辑,职责过重;

增加系统中类的个数,增加系统复杂度和理解难度;

违反了设计模式中的开闭原则,新增产品需修改工厂逻辑;

简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

Nacos Client的简单工厂模式

在Nacos的client中,提供了一个NacosFactory的工厂类,该类统一提供了创建ConfigService(配置中心服务)、NamingService(注册中心服务)和NamingMaintainService(注册中心实例操作服务)的实例化方法。


在源码中可以看到是通过如下方式创建NamingService的:


NamingService namingService = NacosFactory.createNamingService(properties);

1

NacosFactory的部分源码:


public class NacosFactory {
    public static ConfigService createConfigService(Properties properties) throws NacosException {
        return ConfigFactory.createConfigService(properties);
    }
    public static NamingService createNamingService(Properties properties) throws NacosException {
        return NamingFactory.createNamingService(properties);
    }
    // ... 省略其他方法
}

乍一看该类的名字,你可能已经意识到它是工厂模式中的一种。但仔细对比会发现,哪一种好像都不是。


首先,我们来看最终创建出来的NamingService和ConfigService,它们各自独立,并不属于同一个抽象产品类。那这样创建出来也叫简单工厂模式吗?


这里要注意前面定义简单工厂模式时说过“被创建的实例通常都具有共同的父类”,这里的“通常”也就是说大多数情况下是这样的,也允许不实现自同一个接口或抽象类。


其次,我们会发现,NacosFactory中也没有根据方法参数进行不同的对象进行创建,而是直接提供了多个方法来创建不同的对象实例。这又是为什么呢?


这样设计可能出于三个目的:


第一,无论NamingService还是ConfigService,它们本身已经对应的工厂类ConfigFactory和NamingFactory了,如果需要单独创建其实是可以直接调用对应的工厂类的;


第二,NacosFactory存在的目的,本身就是为了达到“聚合”的作用,也就是把所有Nacos相关的服务实例集中对外提供,比如Spring Cloud集成时使用的NacosFactory来创建NamingService,而不是通过NamingFactory来创建。


第三,业务创建比较简单。也就是对于Nacos来说,目前版本中只会提供这三个Service,而不会再多出来其他的,因此开闭原则也就没那么重要了。于是就进行了简化处理。


因此,在使用工厂模式时并不一定非要按标准定义,教条式的进行实现,根据具体的场景可以灵活运用。基本上所有的设计模式都有类似的特点。


Nacos API的简单工厂模式

上面看到的是Nacos Client项目中的简单工厂模式实现,再进一步,我们看看该工厂模式中嵌套的NamingFactory:


public class NamingFactory {
    public static NamingService createNamingService(Properties properties) throws NacosException {
        try {
            Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
            Constructor constructor = driverImplClass.getConstructor(Properties.class);
            return (NamingService) constructor.newInstance(properties);
        } catch (Throwable e) {
            throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
        }
    }
    // ...
}

在NamingFactory中的实现,才更接近标准的简单工厂模式。因为它提供的createNamingService方法,返回的是抽象产品类NamingService(接口)。而在该方法内部呢,才真正创建了它的实现类,虽然实现类只有一个。


小结

学习本文其实想给大家传递两个观点:第一,阅读源码时,其实我们可以多思考一步,比如看看它用到了什么设计模式或知识点;第二,学习设计模式时一定要活学活用,真实的实践环境变化完全,没必要刻板的按照概念来。活学活用,灵活变动,才达到了学习的最高境界。



目录
相关文章
|
安全 Java Spring
SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六)
SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六)
187 0
|
3月前
|
消息中间件 存储 缓存
超全面Java中的队列(Queue)
Java中的`Queue`接口位于`java.util`包,继承自`Collection`,用于存储待处理的元素,通常遵循FIFO原则。它包含`add`、`offer`、`poll`等方法,支持多种实现类,如`LinkedList`、`PriorityQueue`、`ArrayDeque`、`ConcurrentLinkedQueue`及`BlockingQueue`系列。
339 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月前
|
缓存 Java Nacos
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
如何优雅上线、下线?原来 大厂应用 是这样 优雅发布的!
|
5月前
|
SQL 关系型数据库 MySQL
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
|
5月前
|
Arthas 监控 Java
Arthas dashboard(当前系统的实时数据面板)
Arthas dashboard(当前系统的实时数据面板)
259 12
|
存储 供应链 安全
区块链技术防止交易被篡改的能力主要依赖于其独特的架构和机制
**区块链技术通过分布式存储、去中心化网络、哈希链接、共识机制及加密算法确保交易防篡改。每个区块含前块哈希,篡改将破坏链式结构;共识机制如PoW、PoS保证交易验证;智能合约增强安全性。多层防护保障数据完整性和安全性,支撑其在多个行业中的应用。**
|
11月前
|
存储 缓存 NoSQL
京东面试:亿级黑名单 如何设计?亿级查重 呢?(答案含:布隆过滤器、布谷鸟过滤器)
尼恩,40岁的老架构师,近期在读者交流群中分享了几个大厂面试题及其解决方案。这些问题包括亿级数据查重、黑名单存储、电话号码判断、安全网址判断等。尼恩给出了三种解决方案:使用BitMap位图、BloomFilter布隆过滤器和CuckooFilter布谷鸟过滤器。这些方法不仅高效,还能显著提升面试表现。尼恩还建议大家系统化学习,刷题《尼恩Java面试宝典PDF》,并提供简历修改和面试辅导,帮助大家实现“offer自由”。更多技术资料和PDF可在公众号【技术自由圈】获取。
|
11月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
178 3