前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代理工厂的简单应用

代理工厂的简单应用

作者头像
wsuo
发布2020-09-08 22:02:47
3060
发布2020-09-08 22:02:47
举报
文章被收录于专栏:技术进阶之路

一、简单工厂模式

我们在 JavaWeb 中使用三层架构开发的时候往往有很多耦合的地方,比如下面这个场景。

代码语言:javascript
复制
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 层。

我们可以创建一个工厂类来专门用来创建对象:

代码语言:javascript
复制
public class BeanFactory {

	public static UserService getUserService() {
		return new UserServiceImpl();
	}

	public static UserDao getUserDao() {
		return new UserDaoImpl();
	}
	...
}

于是我们调用的时候就可以直接使用类名调用了。

代码语言:javascript
复制
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 关键字和反射,所以我们可以使用反射解决这个问题。

代码语言:javascript
复制
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 类,我们是否还要写一个同样的方法呢?

代码语言:javascript
复制
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 中的参数,也就是说仅仅是一个字符串。

所以我们可以使用外部配置文件的方式将这些变化的参数单独拎出来,就像下面这样。

代码语言:javascript
复制
# Properties 集合存储该文件的内容
# 他是一个特殊的 Map: key 和 value 都是字符串类型的
userService=edu.lsu.service.impl.UserServiceImpl

这样我们只需要在 java 代码中读取配置文件,获取我们想要的信息,所以之前的代码就可以修改为下面的形式。

因为涉及 IO,IO 操作一般都是比较耗时的操作,为了避免重复访问,我们将这一操作放到静态代码块中,这样一来就可以保证在类加载的时候就读取文件,而且只读取一次。

代码语言:javascript
复制
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 方法,为了做到通用,我们可以定义一个需要用户自己传参的方法。

代码语言:javascript
复制
/**
 * 通用方法
 *
 * @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;
}

这样的话用户在调用的时候就只需要传入键值。

代码语言:javascript
复制
public static void main(String[] args) {
    UserService userService = (UserService) BeanFactory.getBean("userService");
    userService.addUser();
}

没错,这正是 Spring 容器的基本原理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简单工厂模式
  • 二、反射工厂模式
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档