文档章节

面向接口及单例工厂随笔

o
 osc_g8254g7s
发布于 2019/08/19 18:41
字数 1105
阅读 14
收藏 0

面向接口及单例工厂

单例工厂是工厂模式的一种,表示生产出的产品为单例产品。

  在上古web开发中,后端是servlet、service、dao这三层。servlet依赖service,service依赖dao,为什么说依赖,因为该层持有另一层的对象:

//UserServlet
public class UserServlet extends HttpServlet {
    //一个UserServlet中持有一个UserService的实现类对象
    //这里UserService为接口,指向其实现类
    private UserService userService  = new UserServiceImpl();

    //其他代码
    ...
}

//Userservice
public interface UserService{
    private UserDao userDao = new UserDaoImpl();

    ...
}

//UserDao
public interface UserDao{
    //do something
}

  这里为什么将UserService和UserDao声明为接口,并让其引用实现类呢?

  我们要知道的是,Java语言是编译型语言,.java源代码文件是需要编译成.class之后才能运行,如果我们需要切换业务模式,比如需要使用UserService2的业务模式,对于上面用new的方式去创建对象,我们就需要去修改源代码,然后重新编译才能运行。而在项目大的时候,编译是非常耗费时间的。

  对于时间就是金钱的互联网行业,在你编译的时候,你的对手可能就把你的顾客给抢走了,那么有没有一种方法可以快速切换呢?

  有,就是使用反射 + 配置文件的方式来获取对象,当需要不同的对象时只需要修改配置文件,而不用重新编译:

public class UserServlet extends HttpServlet throws Exception {
    //1.读取配置,参数是.properties文件的文件名
    ResourceBundle rb = ResourceBundle.getBundle("service");
    //获取配置文件中的类路径
    String classPath = rb.getString("UserService");
    //通过类路径来获得实例,也就是创建对象
    private UserService userService  = Class.forName(classPath).newInstance();

    //其他代码
    ...
}

service.properties文件:

UserService = com.bilibili.service.impl.UserServiceImpl

  这样当我们想获取不同的UserServiceImpl实例时只需要修改配置文件并重启服务器即可。

  这也是为什么上面使用接口引用其实现类,如果直接使用实现类去引用的话则不能达到这种效果。

  上面的优化后虽然不用重新编译了,但是问题又来了:除了UserServlet中这样反射获得了一个对象,另一个Servlet中——ProductServlet也需要一个类似的ProductService对象,甚至Service中也需要dao对象,这些代码都很像,那么我们可不可以把这一部分给单独抽取出来,作为工具类使用能?

尝试一下:

public class BeansFactory {
    public static Object getInstance(String beanName){

        //1.读取配置
        ResourceBundle rb = ResourceBundle.getBundle("beans");
        String classPath = rb.getString(beanName);
        //2.反射创建对象
        Object o = null;
        try {
            o = Class.forName(classPath).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return o;
    }
}

  我们把这一部分逻辑相似的代码作为一个类的静态方法来使用,这个方法是专门用来生产对象的,我们把这种模式叫做工厂模式

  上面的方式虽然很不错,但还是存在一些问题的:如果不止一个Servlet中需要使用UserService的实现类对象,比如Produce中也需要使用,是不是每个需要使用的地方都要用这种方式持有一个对象呢?
  对于每个需要使用到UserService的地方来说,我们只关注UserService中的方法,我们只是想使用它的功能,我们不关注这个对象怎么创建,也不关注是否是同一个对象,如果每个需要使用到的地方都去 getgetInstance来获得一个对象,这样会造成资源的浪费,那么能不能只创建一个对象来供许多地方使用能?

可以,这就是单例工厂:

public class BeansFactory {
    //我们把创建过的对象使用Map保存起来
    private static Map<String,Object> map = new HashMap<>();

    //这里使用synchronized修饰可以防止多线程问题
    public static synchronized Object getInstance2(String beanName){
        //当有地方需要获得对象时,优先从map中获取
        Object o = map.get(beanName);
        //o为null代表map中没有这种对象,此时我们就去创建这个对象并保存在map中
        if(o == null){
            //如果获取不到,再去反射机制创建,并且保存到map。
            //1.读取配置
            ResourceBundle rb = ResourceBundle.getBundle("beans");
            String classPath = rb.getString(beanName);
            //2.反射创建对象
            try {
                o = Class.forName(classPath).newInstance();
                //保存
                map.put(beanName,o);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        return o;
    }
}

这样我们获取的的就是同一个对象了。

上一篇: Jmeter 模拟高并发
下一篇: CSS组合选择器
o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

VMware——在CentOS中安装VMware Tools

VMware——在CentOS中安装VMware Tools 摘要:本文主要记录了如何在VMware中的CentOS系统中,安装VMware Tools。 安装依赖 查看系统相关信息: 1 [root@localhost ~]# uname -r2 3.10.0-32...

osc_5h5udyht
7分钟前
5
0
SpringCache分布式缓存学习

Spring Cache 简介 Cache接口为缓存的组件规范定义,包含缓存的各种操作集合 Cache接口下Spring提供了各种xxcache的实现;如RedisCache,EhCacheCache,ConcurrentMapCache等; 每次调用需要缓...

osc_4dgu16li
9分钟前
7
0
Python全栈之Flask 简介

前言 Python Web框架里比较有名当属Django,Django功能全面,它提供一站式解决方案,集成了MVT(Model-View-Template)和ORM,以及后台管理。但是缺点也很明显,它偏重。就像是一个装潢好的房...

osc_15fvklrg
10分钟前
5
0
WEB攻击手段及防御第2篇-SQL注入

概念 SQL注入即通过WEB表单域插入非法SQL命令,当服务器端构造SQL时采用拼接形式,非法SQL与正常SQL一并构造并在数据库中执行。 简单的SQL注入的例子: 例1:test123456 or 1=1; 加上or 1=1,...

osc_4hct2n4z
11分钟前
3
0
java 反射机制 (获取父类泛型的类型)getGenericSuperclass

https://blog.csdn.net/jidetashuo/article/details/53538231

Java搬砖工程师
11分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部