设计模式之单例模式
Posted pandty
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之单例模式相关的知识,希望对你有一定的参考价值。
概述:
单例模式(Singleton),是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候,整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。事实上,这些应用都或多或少具有资源管理器的功能。例如,每台计算机可以有若干个打印机,但只能有一个 Printer Spooler(单例) ,以避免两个打印机同时打印一份文件。比如,每台计算机可以有若干通信端口,系统应当集中 (单例)管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。比如Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
定义:
确保一个类只有一个实例,并为整个系统提供一个全局访问点 (向整个系统提供一个获取这个类对象实例的公有方法,且只这个类能直接访问,这个对象只初始化一次,不需要重新实例化对象)。
三特征:
1、单例类只能有一个实例(指向自己实例的私有静态引用)。
2、单例类必须自己创建自己的唯一实例(私有的构造方法)。
3、单例类必须给所有其他对象提供这一实例(以自己实例为返回值的静态的公有方法)。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
2、避免对资源的多重占用
缺点:
1、有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
单例模式类型:
饿汉式(最普遍常用的一种方式,缺点是加载这个类时就会初始化这个实例对象)
public class Singleton { //创建这个类的一个对象(静态私有的全局对象),加载时初始化一次 private static Singleton singleton = new Singleton (); //让构造函数为 private,这样该类就不会被外部类实例化 private Singleton(){} //获取唯一可用的对象的方法 public static Singleton getSingleton(){ return singleton ; } }
懒汉式 :第一次调用才初始化,避免内存浪费(解决饿汉式的不足)
//方法1,存在线程安全 public class Singleton{ //定义这个类的对象,不进行初始化 private static Singleton singleton; //提供私有的构造方法,防止这个类被外部类初始化 private Singleton(){} //提供唯一获取这个类对象的公共静态方法 public static Singleton getSingleton(){ //如果这个对象等于null则进行初始化 if(singleton==null){ singleton=new Singleton(); } return singleton; } } //方法2,给这个唯一的方法进行加锁解决线程安全,但是效率变低 public class Singleton{ //定义这个类的对象,不进行初始化 private static Singleton singleton; //提供私有的构造方法,防止这个类被外部类初始化 private Singleton(){} //提供唯一获取这个类对象的公共静态方法 public static synchronized Singleton getSingleton(){ //如果这个对象等于null则进行初始化 if(singleton==null){ singleton=new Singleton(); } return singleton; } } //方法3, 双重判断解决效率变低问题,完美解决上面2种方式的不足但是实现难度较复杂 public class Singleton{ //定义这个类的对象,不进行初始化 private static Singleton singleton; //提供私有的构造方法,防止这个类被外部类初始化 private Singleton(){} //提供唯一获取这个类对象的公共静态方法 public static Singleton getSingleton(){ //如果这个对象等于null则进行初始化 if(singleton==null){ synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } return singleton; } }
静态内部类方式(也解决上面的缺点,同时更简单的方式)
只有通过显式调用getSingleton方法时,才会进行加载 SingletonHolder 类,初始化Singleton 对象
public class Singleton { //私有静态内部类进行该类的创建和初始化 private static class SingletonHolder { private static final Singleton singleton = new Singleton(); } //私有构造器 private Singleton (){} //公共的方法 public static final Singleton getSingleton() { return SingletonHolder.singleton ; } }
枚举方式
描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
public enum Singleton { //全局属性 要调用的话直接Singleton.INSTANCE就行 INSTANCE; //业务逻辑 public void whateverMethod() { } }
一般情况下,建议使用饿汉式和懒汉式第二种方式。只有在要明确实现 lazy loading 效果时,才会使用静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用最后枚举方式。如果有其他特殊的需求,可以考虑使用第 懒汉式第三种方式。
以上是关于设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章