来源丨炭烧生蚝
juejin.im/post/5cc1a4755188252b4a5c30b0
索尔科姆港,英国 (© Devon and Cornwall Photography)
引 入
假设有一个司机, 需要到某个城市, 于是我们给他一辆汽车
如果我们希望给到这个司机的始终是一辆车, 应该怎么做? ( 单例 )
首先我们不能让司机自己通过 new产生一辆汽车, 而是应该通过调用 Car类中的某个方法对外提供车.
简单工厂
下面考虑, 如果我们不希望只有汽车这种交通工具, 我们希望可以定制交通工具, 并定制生产交通工具的流程, 应该怎么做?
一旦产生由汽车到交通工具这样的概念, 就应该想到多态. 我们可以定义一个 Moveable 接口, 在接口中声明 run() 方法, 所有的交通工具类都实现该接口.
对于定制生产流程, 我们可以通过一个工厂进行生产对应的交通工具.
抽象工厂
下面把简单工厂的画面从脑海中清空, 讲述另一种工厂实现.
我们假设开头的司机不是一个普通的司机, 他除了需要一种交通工具以到达某个城市外, 他还需要一把AK47, 并且还需要一个苹果以备路上不时之需.
所以我们需要给他一个工厂来制造这一系列产品.
为了提高可扩展性, 我们还希望不同的工厂可以制作不同系列的产品, 比如上面说的A工厂制造的是汽车, AK47, 苹果; 而B工厂制造的是飞机, 火箭炮, 旺仔小馒头.
总结一下, 抽象工厂和简单工厂各有什么优劣?
抽象工厂能够生产一系列产品, 也能方便地替换掉一系列产品, 但是如果想要在产品系列中添加多一个品种将会非常麻烦. 比如说在上面的系列产品中添加一个盔甲抽象类, 那么抽象工厂以及对应的实现都要修改源码了.
而简单工厂能够灵活的生产但一个品种的产品, 但是如果生产的品种较多, 会出现工厂泛滥的问题.
两者优劣互补, 那么有没有可以兼容两者优点的工厂实现呢? 下面看 spring 的工厂实现, 它给出了一种解决方案.
Spring的Bean工厂
我们再次考虑最原始的情况, 有一个 Moveable 接口, 里面有 run 方法, Car 小汽车类实现了该接口.
在 Spring 的 bean 工厂中, 新对象不是通过 new 关键字获取的, 而是通过配置文件获取的.
具体的过程是: 先读取配置文件获得该类的 class 对象, 然后通过 class 对象创建具体的实例对象.
上面是对 Spring 中 bean 工厂使用的模拟, 下面我们使用真实的 Spring 来生成 Car 对象, 对比一下.
经过对比我们发现我们自己写的简单工厂和 Spring 的 bean 工厂在使用上没有什么区别, 确实 Spring 使用起来就是这么简单, 下面我们模拟一下 Spring 的 bean 工厂实现.
模拟 Spring工厂实现
模拟 IOC:
都说 Spring 是个 bean 容器, 以下的代码将展示它是如何生成 bean , 并把 bean 放入容器中供用户获取的.
思路比较简单:
创建 BeanFactory 工厂接口, 添加方法 getBean() .
创建 BeanFactory 的实现类 ClassPathXmlApplicationContext . 将在该实现类中展示 IOC 的具体实现.
ClassPathXmlApplicationContext 需要一个 container 容器存放创建的 bean 对象, 这里使用 HashMap 实现.
在 ClassPathXmlApplicationContext 的构造方法中读取 spring 的配置文件, 这里使用到了 dom4j . 读取配置文件后根据 bean 的 class 属性使用反射创建出 bean 对象. 然后把 id 和 bean 对象分别作为 key 和 value 添加到容器中.
当工厂被调用 getBean() 方法时, 从容器中找到对应的 bean 并返回.
后 记
若有错误或者不当之处,可在本公众号内反馈,一起学习交流!
更多热文在此:
● Spring Boot 系列实战文章合集(源码已开源)
● 程序员写简历时必须注意的技术词汇拼写
● 基于Spring Security OAuth2 的SSO单点登录+JWT权限控制实战
● 从一份配置清单详解Nginx服务器配置
● 如何在Windows下像Mac一样优雅的开发
● Docker容器可视化监控中心搭建
● 利用ELK搭建Docker容器化应用日志中心
● RPC框架实践之:Google gRPC
● 一文详解 Linux系统常用监控工具
更多 务实、能看懂、可复现的 技术文章尽在公众号 CodeSheep ,欢迎扫码订阅,第一时间获取更新 :arrow_down::arrow_down::arrow_down: