zoukankan      html  css  js  c++  java
  • 创建型模式-单例模式(确保对象唯一性)

    1. 定义

    单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

    2. 结构

    单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是结构最简单的设计模式一,在它的核心结构中只包含一个被称为单例类的特殊类。单例模式结构如图所示:

    单例模式

    • Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

    3. 代码实现

    1. 普通单例模式,多线程调用会出现创建了多个对象
    public class Singleton {
    
    	private static Singleton singleton;
    
    	private Singleton() {
    	}
    
    	public static Singleton getInstance() {
    		if (singleton == null) {
    			singleton = new Singleton();
    		}
    		return singleton;
    	}
    
    }
    
    1. 饿汉单例模式,是实现起来最简单的单例类,当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。可确保单例对象的唯一性。结构图和代码如下:

    饿汉单例

    public class EagerSingleton {
    
    	private static EagerSingleton eagerSingleton = new EagerSingleton();
    
    	private EagerSingleton() {
    	}
    
    	public static EagerSingleton getInstance() {
    		return eagerSingleton;
    	}
    
    }
    
    1. 懒汉单例模式,在第一次调用getInstance()方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载(Lazy Load)技术,即需要的时候再加载实例,为了避免多个线程同时调用getInstance()方法,结构图和代码如下:

    懒汉单例模式

    public class LazySingleton {
    
    	private static LazySingleton instance = null;
    
    	private LazySingleton() {
    	}
    
    	//锁的范围过大,性能降低
    	synchronized public static LazySingleton getInstance() {
    		if (null == instance) {
    			instance = new LazySingleton();
    		}
    		return instance;
    	}
    
    }
    

    上面的懒汉单例使用synchronzed进行线程锁,范围过大,影响性能,可以使用双重检查锁定(Double-CheckLocking)来实现懒汉式单例类,代码如下:

    class LazySingleton2 {
    
    	//volatile保证多线程间共享变量的可见性
    	private volatile static LazySingleton2 instance = null;
    
    	private LazySingleton2() {
    	}
    
    	//双重检查锁定(Double-Check Locking)
    	public static LazySingleton2 getInstance() {
    		//第一重判断
    		if (null == instance) {
    			//锁定代码块
    			synchronized (LazySingleton2.class) {
    				//第二重判断
    				if (null == instance) {
    					instance = new LazySingleton2();
    				}
    			}
    		}
    		return instance;
    	}
    }
    

    饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控
    制烦琐,而且性能受影响。

    还有一种更好的单例实现方式,称之为Initialization Demand Holder (IoDH)的技术,既可以实现延迟加载,又可以保证线程安全,不影响系统性能.在IoDH中,我们在单例类中增加一个静态(static)内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用,实现代码如下:

    class Singleton2 {
    
    	private Singleton2() {
    	}
    
    	private static class HolderClass {
    
    		private final static Singleton2 instance = new Singleton2();
    	}
    
    	public static Singleton2 getInstance() {
    		return HolderClass.instance;
    	}
    
    }
    

    4. 优缺点

    • 优点
    1. 单例模式提供了对唯一实例的受控访问。
    2. 可节约系统资源,对于需频繁创建和销毁的对象单例模式可提高系统的性能。
    3. 允许可变数目的实例,可私用单例控制相似办法来获得指定个数的对象实例。
    • 缺点
    1. 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
    2. 单例类的职责过重,在一定程度上违背了“单一职责原则”。
    3. 自动垃圾回收技术可能会导致单例对象状态的丢失。

    5. 适用场景

    1. 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
    2. 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

    6. 个人理解

    单例模式可确保只有一个实例对象,其提供了实例的全局访问点来获得该实例,为了避免多线程访问的隐患,可使用饿汉单例模式和IoDH技术的懒汉单例模式。

    参考

    1. Java设计模式-刘伟
  • 相关阅读:
    软件测试的常阅博客
    使用Silverlight操作ASPNETDB数据库
    在Silverlight中实现跨域访问
    部署Silverlight应用时遇到的问题
    如何在WPF和Silverlight中取得DataTemplate中的命名元素
    [转] Silverlight Navigation(多页面切换、传值)
    如何让Button点击后不得focus
    VS2010无法连接到SQlServer2008 Database file
    常用的gulp插件
    Android通过http协议POST传输方式
  • 原文地址:https://www.cnblogs.com/ading-blog/p/9667355.html
Copyright © 2011-2022 走看看