zoukankan      html  css  js  c++  java
  • 程序设计之 同步静态方法和单例模式的选择

    一、问题的引出

    目的:设计一个加密的工具类。

    写法一:【单例模式】

    public class CipherUtils {
    	private List key;
    	private static CipherUtils instance;
    	private CipherUtils(String... args){
    		// TODO 比较复杂的初始化KEY的过程
    	} 
    	public static boolean initInstance(String... args){
    		instance = new CipherUtils(args);
    		return true;
    	}
    	public static CipherUtils getInstance(){
    		return instance;
    	}
    	
    	// 正在用到的加密方法
    	public String doCipher(String... args){
    		// TODO
    		Map map = new HashMap();
    		map.put("key", key);
    		return null;
    	}
    }
    

    》》调用方法:

    CipherUtils cu= CipherUtils.getInstance();

                    cu.doCipher(...);

    写法二:【静态方法模式】  

    public class CipherUtils {
    	private static List key;
    	// 正在用到的加密方法
    	public static String doCipher(String... args){
    		// TODO
    		Map map = new HashMap();
    		map.put("key", key);
    		return null;
    	}
    	// 比较复杂的初始化KEY的过程
    	public static void initKey(String... args){
    		// TODO
    	}
    }
    

    》》调用方法:CipherUtils.doCipher(...);

    注意以上例子,只是一个模拟,真实情况 类的属性可能不止一个,可能有三个以上属性。

    写法一的特点:

    1、使用时调的方法都是非static的(doCipher等等)

    2、类的属性都是非static的。

    3、拥有单例模式的所有优点。

    写法二的优点:

    1、属性和方法都是static的。

    2、static是全局共享的,所以也拥有单例模式的核心优点。

    另外,还注意到一点,单例模式 有一个比 静态方法模式 更好的地方:

    它可以被继承,方法可以被子类重载,所以扩展性更强。

    例如一个子类SubCipher重载了doCipher方法,那么调用方式如下:

    CipherUtils cu= SubCipher.getInstance();

                    cu.doCipher(...);

    注意到,调用处(第二行)是无需修改代码的。但是如果是静态方法的话,只能重命名一个方法了,而且调用出还要改代码,比如:

    CipherUtils.doCipher_02(...);

    二、问题的研究

      这一部分主要参考了网上3、4篇关于类似问题的讨论。

      比如:

    http://www.blogjava.net/ITdavid/archive/2008/01/22/176939.html

    http://wenku.baidu.com/view/f08eb06125c52cc58bd6befe.html

      具体分析见第三节-总结。

    三、总结

      1、搞清楚单例模式的缺点和优势,不要乱用。

        一般我不用单例模式,因为这样增加了代码管理成本。但是以下几个场景最好用单例模式:

    1)场景一:类可能会有继承、方法可能需要重载。(Spring里面有些东西就是这样设计的)

    2)场景二:类的所有属性需要保持一致性,(要么都改变,要么都不改变),且这个类的方法较多(5个以上)。单例模式实现这个功能就比较方便,直接把原来缓存的static实例对象整体替换掉,重新new一个就可以了,

    但是如果用静态方法来实现,则在更新属性时,需要停止所有的static方法被调用,也就意味着,要在所有的方法中加上synchronized关键字,即:单例模式只需要同步getInstance这个方法就可以,而静态方法模式,需要同步所有的方法。

    如果类的实例方法不多,在5个以内,那其实给每个方法都加上synchronized关键字那也无所谓,反正效率上讲,静态方法还稍微高一些,但是如果方法多了,则还是采用单例模式吧。

      2、就我上面,那个问题而言,最好是采用静态方法模式,因为只有一个doCipher方法,不符合场景二,而且本身是个工具类,无需类的继承,所以也不符合场景一。

            PS:参考Struts的源码,我们其实可以对同步静态方法进行适当改造。单例模式有一个缺点是,无论你做什么操作,都需要同步,性能上稍微低了一点点,

    静态方法则可以采用一种“读写锁”的模式,当有“写操作”时,则不允许其他操作,当只有“读操作时”,则不允许“写操作”但是允许其他读操作。其实现可以参考struts的源码:

    com.opensymphony.xwork2.util.logging.LoggerFactory;

    java.util.concurrent.locks.ReadWriteLock;

    java.util.concurrent.locks.ReentrantReadWriteLock;

  • 相关阅读:
    什么是枚举?有什么作用?有什么好处?
    java获取某个范围内的一个随机数
    java中普通代码块,构造代码块,静态代码块的区别及代码示例
    Oracle数据库迁移
    linux下修改文件权限
    <%@ include file="">和<jsp:include file="">区别
    JAVA常见异常解析
    jdk环境变量配置
    jstl中fmt标签详解
    jsp脚本元素
  • 原文地址:https://www.cnblogs.com/zollty/p/3287915.html
Copyright © 2011-2022 走看看