面向接口及单例工厂随笔

面向接口及单例工厂

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

??在上古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;
    }
}

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

原文地址:https://www.cnblogs.com/lixin-link/p/11378874.html

时间: 2024-10-15 04:50:16

面向接口及单例工厂随笔的相关文章

C++实现一个线程安全的单例工厂

我们见到经常有人用 static 局部对象的方式实现了类似单例模式,最近发现一篇文章明确写明 编译器在处理  static局部变量的时候 并不是线程安全的 !!! http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx 于是实现了一个单例工厂  并且是线程安全的 #ifndef SINGLETONFACTORY_H #define SINGLETONFACTORY_H #include "windows.h"

php : MVC 演示(使用单例工厂)

此例子是MVC的简单应用, 要达到的效果如下: 用户列表: 姓名 年龄 学历 兴趣 出生地 账号创建时间 操作 keen 20 高中 篮球,足球 广东 2016-11-08 10:00:31 删除 andi 30 本科 乒乓球 上海 2016-11-22 10:00:55 删除 ddddddd 40 初中 台球 广州 2016-11-10 12:20:49 删除 eeeeeee 34 大专 慢跑 深圳 2016-11-15 12:21:26 删除 当前用户总数: 4 一.设计表 create t

设计模式:简单工厂和单例工厂

1 <?php 2 /** 3 * 纯粹工厂类 4 */ 5 /*class Factory { 6 public static function getOBJ($class_name) { 7 include_once './'.$class_name.'.class.php'; 8 return new $class_name; //可变类 9 } 10 } 11 */ 12 13 /** 14 * cun工厂类 15 */ 16 class Factory { 17 /* 18 生产单例对

python实现单例工厂模式

class CarFactory: '''python实现单例工厂模式''' __obj = None __flg_init = True def __new__(cls, *args, **kwargs): if cls.__obj is None: cls.__obj = object.__new__(CarFactory) return cls.__obj def __init__(self): if CarFactory.__flg_init: print('工厂产生了') CarFac

PHP设计模式 二 (单例 工厂 注册)

单例模式 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案. 数据库单例示例: <?php namespace Components; class Database { protected static $db; private function __construct(){ //单列模式

java设计模式(1)-------单例,工厂,值对象,装饰模式

      java设计模式(1) 先简单的介绍下设计模式吧:是一种解决问题的一种行之有效的思想:用于解决特定环境下.重复出现的特定问题的解决方案. 那为什么我们需要学习设计模式呢? 1.设计模式都是一些相对优秀的解决方案,很多问题都是典型的.有代表性的问题,学习设计模式,我们就不用自己从头来解决这些问题,相当于在巨人的肩膀上,复用这些方案即可,站的高看到远,就是要站在巨人的肩膀上把他们踩下去,嘿嘿. 2.设计模式已经成为专业人士的常用词汇,不懂不利于交流,能让你变得很牛逼哦. 3.能让你设计的

编程常用设计模式详解--(上篇)(工厂、单例、建造者、原型)

参考来自:http://zz563143188.iteye.com/blog/1847029 一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 二.设计模式的六大原则 1

浅谈应用工厂模式和单例在Android中实现业务隔离

Android中写应用,一样需要考虑到降低耦合性的问题,还有一些其他问题,比如App的增量式更新,业务变更的便捷实现等等,都会有工厂模式和单例的身影. 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式.因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改

编程经常使用设计模式具体解释--(上篇)(工厂、单例、建造者、原型)

參考来自:http://zz563143188.iteye.com/blog/1847029 一.设计模式的分类 整体来说设计模式分为三大类: 创建型模式.共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.訪问者模式.中介者模式.解释器模式. 二.设计模式的六大原则 1