参考的学习视频→https://b23.tv/av47952931/p82
◆传统方式
我们创建一个maven工程(不选择任何骨架),在pom文件中添加<packaging>jar</packaging>标签,设置打包方式为jar
![](https://i-blog.csdnimg.cn/blog_migrate/29ef6e17056fc7034553b6b4a3c718d2.png)
新建IAccountService接口,在此接口内写一个用来模拟保存账户的方法
![](https://i-blog.csdnimg.cn/blog_migrate/807f6b5591081f07fb46c83bd6a1783b.png)
新建一个IAccountDao接口作为账户的持久层接口,仍然写一个方法来模拟账户保存的操作
![](https://i-blog.csdnimg.cn/blog_migrate/73b179b54cf9fe9ecc6a92e4e4639559.png)
新建一个AccountDaoImpl类继承IAccountDao接口,并实现该接口的saveAccount()方法(这里用打印一个字符串代替)
![](https://i-blog.csdnimg.cn/blog_migrate/5a26edf584b98992413ade8d5bed0d9c.png)
新建一个AccountServiceImpl类继承IAccountService接口作为账户的业务层实现类
![](https://i-blog.csdnimg.cn/blog_migrate/5aa00984ac157774f66a01e82ab43e66.png)
新建一个Client类模拟表现层,在这里编写main函数来调用业务层,运行工程,程序正常运行
![](https://i-blog.csdnimg.cn/blog_migrate/c862c207b97680f5690e12c300b1747c.png)
但是此代码的不足之处在于有很强的耦合性(因为用了new的方式创建对象,一旦删掉了某一个类,代码就无法正常编译)
◆下面用工厂模式来解决耦合的问题
~首先了解一些知识~
Bean:在英语中,有可重用组件的含义
JavaBean:用java语言编写的可重用组件
JavaBean > 实体类
- 作用:创建service和dao对象
- 实现方法:
- 需要一个配置文件来配置 service和dao
- 通过读取配置文件中的内容来反射创建对象
▶配置内容:唯一标识=全限定类名(key=value) ◀▶配置文件类型:xml或properties ◀
于是我们新建一个BeanFactory类,用来创建Bean
![](https://i-blog.csdnimg.cn/blog_migrate/9d7aa58e0b86626aa028be8ce37742aa.png)
创建bean.properties文件并配置参数,我们把com.example.service.impl.AccountServiceImpl 和com.example.dao.impl.AccountDaoImpl这两个类作为参数写在了配置文件中
![](https://i-blog.csdnimg.cn/blog_migrate/051b0d0934c01ab673c20abcc1da4a11.png)
在BeanFactory中定义一个Properties对象,使用静态代码块为Properties对象赋值,并定义一个static方法返回根据名称获取的Bean
![](https://i-blog.csdnimg.cn/blog_migrate/0861bb5b79285706c910e375c0f2a028.png)
修改Client类的main方法,将new对象改为反射的方式创建对象
![](https://i-blog.csdnimg.cn/blog_migrate/caf38c092cb516881cfbec9bd78d1a3b.png)
同样地,修改AccountServiceImpl类
![](https://i-blog.csdnimg.cn/blog_migrate/57859bf55425d530e92539a2b018ee16.png)
点击运行,程序正常运行
![](https://i-blog.csdnimg.cn/blog_migrate/4bbb09ee8f3ba276c0d629f4ae89a301.png)
这时如果我们再删除掉AccountDaoImpl这个类
![](https://i-blog.csdnimg.cn/blog_migrate/2c33f403239897d628bcc1457b90d502.png)
再次运行,程序仍然编译通过,只是在运行时抛出无法找到类的异常
![](https://i-blog.csdnimg.cn/blog_migrate/45200565e893b5f121f22718a39ff1fa.png)
◆分析工厂模式存在的问题并修改
为了说明问题,我们在Client类的main方法中加入一个for循环,一共取出5个Bean并打印它们的内存首地址。运行程序,发现它们的首地址各不相同
![](https://i-blog.csdnimg.cn/blog_migrate/c61127dad03e10a6433e309e5f801d51.png)
这说明此时的对象是多例的,也就是说每次getBean都创建了一个新的对象,这是因为getBean方法中,newInstance()方法每次都会调用默认构造函数创建对象
![](https://i-blog.csdnimg.cn/blog_migrate/90cc455b94a90b13afa24e7011db30b8.png)
如果需要创建单例对象(即对象只被创建一次,从而类中的成员只会初始化一次,每次get到的都是同一个对象),就必须把创建的对象存起来,于是我们定义一个map用于存放我们要创建的对象,我们把它称之为容器
![](https://i-blog.csdnimg.cn/blog_migrate/862b56b2e60c7db0826d2d3ae1eeba12.png)
我们在静态代码块中根据配置文件中的所有key分别反射创建对象,然后存入Map中
![](https://i-blog.csdnimg.cn/blog_migrate/5aa6e0599d3c09d61aaa208d504ad0a0.png)
这样一来,我们的getBean方法只用将容器中对应的Bean返回即可
![](https://i-blog.csdnimg.cn/blog_migrate/a6c7ec7fe5f961616de7b9778010fd16.png)
运行程序,我们发现打印出5次获得的Bean的首地址相同,说明该对象是单例的