JAVA 设计模式 - 单例模式

128 阅读2分钟

单例模式要解决的问题?

保证一个类只有一个实例,并且可以全局访问它。
保证不能实例化多个该对象,必须自行创建该实例

单例类特点

构造方法私有,确保其他类无法通过new 关键字创建它,保证了该类只能有一个实例
有一个静态私有成员变量和静态公有工厂方法,工厂方法负责检查该实例
是否存在,并实例化,然后存储在静态成员变量中

什么时候使用单例模式?

1.要求产生唯一序列号
2.必须存在一个对象,客户端能够从一个公共资源访问到它
3.需要控制实例数目,创建一个对象消耗过多资源,如数据库连接,
  为了节省系统资源的时候。

懒汉式加载

public class Singleton_lazy {

    private static Singleton_lazy lazy = null;

    private Singleton_lazy(){
        // 具体逻辑
    }
    public static synchronized  Singleton_lazy getLazy(){
        if(lazy == null){
            lazy = new Singleton_lazy();
        }
        return lazy;
    }
}

懒汉式加载-双重检查加锁

public class Singleton_lazy {

    //volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量
    private volatile  static Singleton_lazy lazy = null;

    private Singleton_lazy(){
        // 具体逻辑
    }
    public static   Singleton_lazy getLazy(){
        if(lazy == null){
            synchronized(this){
               lazy = new Singleton_lazy();
            }
        }
        return lazy;
    }
}

使用到了volatile关键字来保证数据的可见性

饿汉式加载

public class Singleton_hunger {
    private static Singleton_hunger lazy = new Singleton_hunger();
    private Singleton_hunger(){
        // 具体逻辑
    }
    public static Singleton_hunger getLazy(){
        return lazy;
    }
}

案例

public class XmlConfigReader {
	
	//懒汉式(用的时候再创建),延迟加载
	private static XmlConfigReader instance = null;
	
	//保存jdbc相关配置信息
	private JdbcConfig jdbcConfig = new JdbcConfig();
	
	//构造方法让其private,这就不让外界利用new创建此类实例
	private XmlConfigReader(){
		
		SAXReader reader = new SAXReader();
		//从用来加载类的搜索路径打开具有指定名称的资源,以读取该资源。此方法通过系统类加载器
		InputStream in =Thread.currentThread().getContextClassLoader().getResourceAsStream("sys-conf.xml");
		try{
			
			Document doc = reader.read(in);
			
			//取得jdbc相关配置信息
			Element driverNameElt = (Element)doc.selectObject("/config/db-info/driver-name");
			Element urlElt = (Element)doc.selectObject("/config/db-info/url");
			Element userNameElt  = (Element)doc.selectObject("/config/db-info/user-name");
			Element passwordElt = (Element)doc.selectObject("/config/db-info/password");
			
			//jdbc取得相关的配置
			jdbcConfig.setDriverName(driverNameElt.getStringValue());
			jdbcConfig.setUserName(userNameElt.getStringValue());
			jdbcConfig.setPassword(passwordElt.getStringValue());
			jdbcConfig.setUrl(urlElt.getStringValue());	
		}catch(DocumentException e){
			e.printStackTrace();
		}
	}
	
	//静态方法访问时,直接访问不需要实例化
	public static synchronized XmlConfigReader getInstance(){//synchronized表示同时只能一个线程进行实例化
		if(instance == null){//如果两个进程同时进入时,同时创建很多实例,不符合单例
			instance = new XmlConfigReader();
		}
		return instance;
	}
	
	/*
	 *返回jdbc相关配置
	 *@return 
	 */
	public JdbcConfig getJdbcConfig(){
		return jdbcConfig;
	}
	
	public static void main(String[] args) {
	   //getInstance()是一个静态方法,不需要实例化
		JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();
	}

}