工厂模式(解耦)
1. 耦合性问题
- 耦合性:程序之间的依赖性。
- 编译期依赖:编译时必须提供依赖的类,否则编译不通过。
- 运行期依赖:运行时必须提供依赖的类,否则不能运行。
- 应当减少编译期依赖,使用运行期依赖
- 耦合性越强,维护成本就越高
- 开发时要求:高内聚,低耦合
1.1 耦合性问题现象
- 在web开发中,服务端通常分为三层:web层、service层、dao层
- web层调用service层完成功能:需要new一个Service对象
- service层调用dao层操作数据库:需要new一个dao对象
- 三层之间的耦合性比较强:存在编译期依赖
- service里写死了创建某一个dao对象:一旦dao对象换了,就需要修改service的源码
- web里写死了创建某一个service对象:一旦service对象换了,就需要修改web的源码
1.2 解耦的思路
-
可以使用反射技术,代替
new
创建对象,避免编译期依赖Class clazz = Class.forName("全限定类名"); Object obj = clazz.newInstance();
-
再把全限定类名提取到配置文件中(xml或properties),读取配置文件信息来反射创建对象
//读取配置文件,得到要创建对象的全限定类名;再通过反射技术创建对象 String className = ...; Class clazz = Class.forName(className); Object obj = clazz.newInstance();
2. 使用工厂模式解耦
需求描述
UserService
提供用户相关的功能,需要调用UserDao
完成数据库操作- 使用工厂模式+配置文件的方式,降低它们之间的耦合性
需求分析
需求实现
-
创建项目,导入依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
-
dao层代码
public interface UserDao { void save(); }
public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("UserDaoImpl.save......"); } }
-
service层代码
public interface UserService { void save(); }
public class UserServiceImpl implements UserService { /** * 存在编译期依赖:如果没有UserDaoImpl,代码编译是不通过的。 * 要避免编译期依赖,减少运行期依赖 * 解决思路: * 1. 使用反射技术代替new * 2. 提取配置文件 */ //private UserDao userDao = new UserDaoImpl(); private UserDao userDao = (UserDao) BeanFactory.getBean("userDao"); @Override public void save() { userDao.save(); } }
-
配置文件
beans.properties
userDao=com.itheima.dao.impl.UserDaoImpl
-
工厂类
BeanFactory
public class BeanFactory { private static Map<String, Object> map = new HashMap<>(); static { //类加载时,读取properties文件,把其中所有的bean都创建对象,放到一个容器里 //当需要使用时,直接从容器中获取即可 try { //1.读取配置文件 ResourceBundle bundle = ResourceBundle.getBundle("beans"); Enumeration<String> keys = bundle.getKeys(); while (keys.hasMoreElements()) { String id = keys.nextElement(); String className = bundle.getString(id); Class clazz = Class.forName(className); Object object = clazz.newInstance(); map.put(id, object); } } catch (Exception e) { e.printStackTrace(); } } public static Object getBean(String id){ return map.get(id); } }
小结
- 在UserServiceImpl里需要使用UserDaoImpl对象:
- 原来:自己主动new一个
- 现在:从BeanFactory里获取一个
- 我们编写的工厂:功能太弱
- 如果使用了Spring的工厂:
- 我们需要什么样的对象,只需要进行配置即可
- 配置成什么样,Spring就根据配置创建什么样的对象