2018.3.29 设计模式之单例模式详解

设计模式之单例模式

1.定义/概念

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

应用范围

在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态。

注意:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

2.单例模式中的懒汉式和饿汉式

静态内部类的单利模式

public class Singleton {  
    private Singleton(){}  
    private static Singleton getInstance(){  
        return SingletonHolder.Instance;  
    }  
    /** 
     * 静态内部类 
     */  
    private static class SingletonHolder{  
        private static final Singleton Instance = new Singleton();  
    }  
}  

枚举单例模式

public enum SingletonEnum{  
      INSTANCE;  
      public void doSomething(){  
            System.out.println("do sth.");  
      }  
}  

容器实现单例模式

public class SingletonManager {  
    private static Map<String, Object> objMap = new HashMap<String, Object>();  
    private SingletonManager(){ }  
    //将多种单例类型注入到一个统一的管理类,在使用时根据key获取对象对应类型的对象  
    public static void registerService(String key, Object instance)  
    {  
        if(!objMap.containsKey(key)){  
            objMap.put(key, instance);  
        }  
    }  
    public static Object getService(String key){  
        return objMap.get(key);  
    }  
}  

3.下面演示的是懒汉中的单例模式

为什么要私有化构造方法?

要想在运行期间控制某一个类的实例只有一个,那首先的任务就是要控制创建实例的地方,也就是不能随随便便就可以创建类实例,否则就无法控制创建的实例个数了。现在是让使用类的地方来创建类实例,也就是在类外部来创建类实例。那么怎样才能让类的外部不能创建一个类的实例呢?很简单,私有化构造方法就可以了!

提供获取实例的方法

构造方法被私有化了,外部使用这个类的地方不干了,外部创建不了类实例就没有办法调用这个对象的方法,就实现不了功能处理,这可不行。经过思考,单例模式决定让这个类提供一个方法来返回类的实例,好让外面使用。示例代码如下:

把获取实例的方法变成静态的

MySingleton.java

package com.glut.demo5;

public class MySingleton {
	//设立静态变量
	private static MySingleton mySingleton = null;
	
	//私有化构造函数
	private MySingleton() {
		System.out.println("懒汉式单例模式开始调用构造函数");
	}
	

	//开放一个共有方法,判断是否已经存在实例,又返回,没有就创建
	public static MySingleton getInstance() {
		if(mySingleton == null) {
			System.out.println("懒汉式构造函数的实例当前并没有被创建");
			mySingleton = new MySingleton();
		}else {
			System.out.println("懒汉式构造函数的实例已经被创建");
		}
		System.out.println("方法调用结束,返回单例");
		return mySingleton;
	}
}

Client.java

package com.glut.demo5;

/**
 * 懒汉式单例模式
 * @author qichunlin
 *
 */
public class Client {
	public static void myprint() {
		System.out.println("懒汉式单例模式");
		System.out.println("第一次取得实例");
		MySingleton s1 = MySingleton.getInstance();
		
		System.out.println("第二次取得实例");
		MySingleton s2 = MySingleton.getInstance();
		
		if(s1 ==s2) {
			System.out.println("两个实例相同");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		//懒汉式
		myprint();
	}
}


4.下面演示的是单例模式中的饿汉式

Singleton.java

package com.glut.demo5;

/**
 * 创建一个Singleton类
 * 饿汉式
 * 
 * 饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式
 * 就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了
 * 
 * @author qichunlin
 *
 */
public class SingleObject {
	//创建SingleObject的一个对象,直接创建实例
	private static SingleObject instance = new SingleObject();
	
	//让构造函数为private,这样该类就不会被实例化了
	private SingleObject() {
		super();
	}
	
	//获得唯一可用对象
	public static SingleObject getInstance() {
		return instance;
	}
	
	//显示信息
	public void showMessage() {
		System.out.println("Hello World!");
	}
}

Test.java

package com.glut.demo5;

/**
 * 单例模式 从 singleton 类获取唯一的对象。
 * 
 * @author qichunlin
 *
 */
public class Test {
	public static void main(String[] args) {

		// 不合法的构造函数
		// 编译时错误:构造函数 SingleObject() 是不可见的
		// SingleObject object = new SingleObject();

		// 获取唯一可用的对象
		SingleObject object = SingleObject.getInstance();
		// 显示信息
		object.showMessage();
	}
}

5.单例模式的功能

单例模式的功能是用来保证这个类在运行期间只会被创建一个类实例,另外单例模式还提供了一个全局唯一访问这个类实例的访问点,就是那个getInstance的方法。不管采用懒汉式还是饿汉式的实现方式,这个全局访问点是一样的。

对于单例模式而言,不管采用何种实现方式,它都是只关心类实例的创建问题,并不关心具体的业务功能。

6.单例模式的使用场景:

要求生成唯一序列号的环境;
在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。

原文地址:https://www.cnblogs.com/qichunlin/p/8672991.html