设计模式之单例模式

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 效果时,才会使用静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用最后枚举方式。如果有其他特殊的需求,可以考虑使用第 懒汉式第三种方式。

以上是关于设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之单例模式

Java设计模式之单例模式

设计模式之单例模式以及简单代码实现

设计模式之单例设计模式

设计模式之单例模式

设计模式之单例模式