代理工厂的简单应用
一、简单工厂模式
我们在 JavaWeb 中使用三层架构开发的时候往往有很多耦合的地方,比如下面这个场景。
public class UserServiceImpl implements UserService {
private UserDaoImpl userDao = new UserDaoImpl();
@Override
public void addUser() {
userDao.addUser();
}
@Override
public void deleteUser() {
userDao.deleteUser();
}
}
在 Service 中调用 Dao 层,必须要 new 一个 Dao 对象,在 Controller 中也是如此调用 Service 层。
我们可以创建一个工厂类来专门用来创建对象:
public class BeanFactory {
public static UserService getUserService() {
return new UserServiceImpl();
}
public static UserDao getUserDao() {
return new UserDaoImpl();
}
...
}
于是我们调用的时候就可以直接使用类名调用了。
public class UserServiceImpl implements UserService {
private UserDaoImpl userDao = BeanFactory.getUserDao();
@Override
public void addUser() {
userDao.addUser();
}
@Override
public void deleteUser() {
userDao.deleteUser();
}
}
但是还有新的问题,并没有根本的解决耦合问题,因为只是将耦合的地方换了一个位置,在 BeanFactory 中仍然有耦合出现,还是使用到了 new 关键字,所以我们要继续解决这个问题。
二、反射工厂模式
我们知道在 java 中创建对象有两种方式,分别是使用 new 关键字和反射,所以我们可以使用反射解决这个问题。
public static UserDao getUserDao() {
UserDao userDao = null;
try {
Class clazz = Class.forName("edu.lsu.dao.impl.UserDaoImpl");
userDao = (UserDao) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return userDao;
}
这里使用了 Class.forName("edu.lsu.dao.impl.UserDaoImpl")
去加载类,然后调用它的 newInstance
方法创建对象。
但是如果我们还需要一个方法来获取 UserServiceImpl 类,我们是否还要写一个同样的方法呢?
public static UserService getUserService() {
UserService userService = null;
try {
Class<?> clazz = Class.forName("edu.lsu.service.impl.UserServiceImpl");
userService = (UserService) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return userService;
}
其实没必要,我们发现这两个方法有很大的相似之处,变化的地方仅仅是 Class.forName
中的参数,也就是说仅仅是一个字符串。
所以我们可以使用外部配置文件的方式将这些变化的参数单独拎出来,就像下面这样。
# Properties 集合存储该文件的内容
# 他是一个特殊的 Map: key 和 value 都是字符串类型的
userService=edu.lsu.service.impl.UserServiceImpl
这样我们只需要在 java
代码中读取配置文件,获取我们想要的信息,所以之前的代码就可以修改为下面的形式。
因为涉及 IO,IO 操作一般都是比较耗时的操作,为了避免重复访问,我们将这一操作放到静态代码块中,这样一来就可以保证在类加载的时候就读取文件,而且只读取一次。
public class BeanFactory {
private static Properties env = new Properties();
// 使用静态代码块一次性的读取资源,避免重复访问
static {
// 1.获取 IO 流
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
try {
// 2.将配置文件封装到 Properties 中
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static UserService getUserService() {
UserService userService = null;
try {
Class<?> clazz = Class.forName(env.getProperty("userService"));
userService = (UserService) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return userService;
}
}
当然这里目前仅仅有一个 getUserService
方法,为了做到通用,我们可以定义一个需要用户自己传参的方法。
/**
* 通用方法
*
* @param key 键值
* @return 返回obj
*/
public static Object getBean(String key) {
Object obj = null;
try {
Class<?> clazz = Class.forName(env.getProperty(key));
obj = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
这样的话用户在调用的时候就只需要传入键值。
public static void main(String[] args) {
UserService userService = (UserService) BeanFactory.getBean("userService");
userService.addUser();
}
没错,这正是 Spring 容器的基本原理。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 掌握好这几个css属性,少写100行js代码
- Flash写入性能下降问题
- 如何用开源项目申请 JetBrains 产品的 license
- npm -i 与npm install -S与-D的区别以及dependencies与devDependencies的区别
- axios POST提交数据的三种请求方式写法
- 将资源文件编译成源代码文件
- 一道简单的笔试题_时钟切换电路(Glitch-free clock switching circuit)
- 【STM32F429开发板用户手册】第26章 STM32F429的定时器应用之TIM1-TIM14的中断实现
- 【STM32F407开发板用户手册】第26章 STM32F407的定时器应用之TIM1-TIM14的中断实现
- ATTR节点应用
- 等待队列
- samba
- gpio_key按键驱动
- Linux中断下半部实现机制
- linux中led驱动(设备树)编程笔记