在java程序里,你有没有过这样的想法:
经常new 一个实例,很是麻烦,有些无状态的类,完全可以整个系统里只new一次的,单例模式恰恰可以解决这个问题,可是每个类都写成单例,成本有太大。。。
这个时候,不妨写个单例工厂来试试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.bj58.activity.bj58eshd.service; import java.util.HashMap; import java.util.Map; /** * 对一些需要单例创建并管理一些非状态的类对象 * 被创建的类必须满足的条件: * 1.类本身具有零参数的构造方法 * 2.构造方法不能是private类型 * 3.请注意有状态值的类 * @author Liu Zhaokao * @QQ 3024537 * @Datetime 2015-3-26 上午10:45:10 */ public class ServiceFactory { /** * 所有的类实例 * key: class * value : Object */ private static Map<Class<?>, Object> classMap = new HashMap<Class<?>, Object>(); public static <T> T getInstance(Class<T> target){ if(!classMap.containsKey(target)){ synchronized (ServiceFactory.class) { if(!classMap.containsKey(target)){ try { /** * 前提是 构造方法不是私有的 */ classMap.put(target, target.newInstance()); } catch (Exception e) { } } } } return (T)classMap.get(target); } } |
这样妥妥的,,其实仔细看代码不难看出,原理是利用泛型,将所有类的实例放到一个map里,虽然在put的时候用的synchronized线程同步,保证安全,可是难免会有线程多线程不同步的问题,,改进办法之一就是用 ConcurrentHashMap 替代:
1 |
private static Map<Class<?>, Object> classMap = new ConcurrentHashMap<Class<?>, Object>(); |
其实,本汉需要解释的是,其实就算是多个线程不同步,造成的代价无非是多new 了几次,对性能上的影响也不大,并且getInstance方法里在put的时候,已经保证了put的线程同步,所以此处线程安全的风险不是太大。。
后来有个小伙伴来问我,这个单例工厂,只是能new一些有默认的public的空构造方法的类,,,如果那样,其他地方也可以通过new来实例化这些类,那可不可以把这些类的构造方法写成private的呢,让别人只能通过单例工厂类来实例化????
答案是肯定的,java里有种反射机制,就可以调用类的私有方法。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public static <T> T getInstance(Class<T> target){ if(!classMap.containsKey(target)){ synchronized (ServiceFactory.class) { if(!classMap.containsKey(target)){ try { /** * 前提是 构造方法不是私有的 */ // classMap.put(target, target.newInstance()); /** * 当构造方法是private时 */ Constructor<T> constructor = target.getDeclaredConstructor(); constructor.setAccessible(true); T classInstance = (T)constructor.newInstance(); classMap.put(target,classInstance); } catch (Exception e) { } } } } return (T)classMap.get(target); } |
转载请注明:刘召考的博客 » 单例模式的升级–单例工厂管理实例化