【设计模式之美】【建造型】工厂模式实战:如何设计一个DI框架;梳理流程,通过面向接口解耦对象创建

设计模式小思考:
梳理清楚业务逻辑之后,比如主流程是什么,流程中第一步、第二步…等每一步都封装到方法、某些步骤需要根据业务有不同的实现,这时使用面向接口编程来解耦对象实现。

通过本文的学习你能够了解DI容器的设计思路,并通过学习它的抽象逻辑,进一步了解面向接口的编程思路

一. 工厂模式和 DI 容器有何区别?

设计思想

实际上,DI 容器底层最基本的设计思路就是基于工厂模式的。DI 容器相当于一个大的工厂类,负责在程序启动的时候,根据配置(要创建哪些类对象,每个类对象的创建需要依赖哪些其他类对象)事先创建好对象。当应用程序需要使用某个类对象的时候,直接从容器中获取即可。正是因为它持有一堆对象,所以这个框架才被称为“容器”。

对象规模

DI 容器相对于我们上节课讲的工厂模式的例子来说,它处理的是更大的对象创建工程。上节课讲的工厂模式中,一个工厂类只负责某个类对象或者某一组相关类对象(继承自同一抽象类或者接口的子类)的创建,而 DI 容器负责的是整个应用中所有类对象的创建。

负责的工作

除此之外,DI 容器负责的事情要比单纯的工厂模式要多。比如,它还包括配置的解析、对象生命周期的管理。接下来,我们就详细讲讲,一个简单的 DI 容器应该包含哪些核心功能。

 

二. DI 容器的核心功能有哪些?

总结一下,一个简单的 DI 容器的核心功能一般有三个:配置解析、对象创建和对象生命周期管理。

1. 配置解析:解耦对象创建

作为一个通用的框架来说,框架代码跟应用代码应该是高度解耦的,DI 容器事先并不知道应用会创建哪些对象,不可能把某个应用要创建的对象写死在框架代码中。

我们可以将需要由 DI 容器来创建的类对象和创建类对象的必要信息(使用哪个构造函数以及对应的构造函数参数都是什么等等),放到配置文件中。容器读取配置文件,根据配置文件提供的信息来创建对象。

下面是一个典型的 Spring 容器的配置文件。
Spring 容器读取这个配置文件,解析出要创建的两个对象:rateLimiter 和 redisCounter,并且得到两者的依赖关系:rateLimiter 依赖 redisCounter。

public class RateLimiter {
   
   
  private RedisCounter redisCounter;
  public RateLimiter(RedisCounter redisCounter) {
   
   
    this.redisCounter = redisCounter;
  }
  public void test() {
   
   
    System.out.println("Hello World!");
  }
  //...
}

public class RedisCounter {
   
   
  private String ipAddress;
  private int port;
  public RedisCounter(String ipAddress, int port) {
   
   
    this.ipAddress = ipAddress;
    this.port = port;
  }
  //...
}

配置文件beans.xml:
<beans>
   <bean id="rateLimiter" class="com.xzg.RateLimiter">
      <constructor-arg ref="redisCounter"/>
   </bean>
 
   <bean id="redisCounter" class="com.xzg.redisCounter">
     <constructor-arg type="String" value="127.0.0.1">
     <constructor-arg type="int" value=1234>
   </bean>
</beans>

 

2. 对象创建

  1. 对于对象创建,我们提供一个工厂类,将所有对象的创建都放到这一个工厂类中,比如 BeansFactory。

  2. 代码线性膨胀问题:如果要创建的对象非常多,我们可以使用反射机制,在程序运行的过程中,动态的加载类、创建对象,不需要在代码中写死要创建哪些对象。所以,不管是创建一个对象还是十个对象,BeansFactory
    工厂类代码都是一样的。

 

3. 对象的生命周期管理

生命周期大致我们可以做如下事情:

  1. 根据scope来确定每次返回新的对象还是事先建立好的(单例)对象。 scope=prototype 表示返回新创建的对象,scope=singleton 表示返回单例对象。

  2. 配置对象是否支持懒加载。如果 lazy-init=true,对象在真正被使用到的时候才被被创建。

  3. 创建后和销毁前。我们还可以配置对象的 init-method 和 destroy-method 方法,比如 init-method=loadProperties(),destroy-method=updateConfigFile()。

  • DI 容器在创建好对象之后,会主动调用 init-method 属性指定的方法来初始化对象。
  • 在对象被最终销毁之前,DI 容器会主动调用 destroy-method 属性指定的方法来做一些清理工作,比如释放数据库连接池、关闭文件。

 

三. 如何实现一个简单的 DI 容器?

核心逻辑只需要包括这样两个部分:配置文件解析、根据配置文件通过“反射”语法来创建对象。

1. 最小原型设计:流程梳理

配置文件beans.xml
<beans>
   <bean id="rateLimiter" class="com.xzg.RateLimiter">
      <constructor-arg ref="redisCounter"/>
   </bean>
 
   <bean id="redisCounter" class="com.xzg.redisCounter" scope="singleton" lazy-init="true">
     <constructor-arg type="String" value="127.0.0.1">
     <constructor-arg type="int" value=1234
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值