设计模式之单例模式

2018-07-11  本文已影响0人  Berry_ad07

对于单例模式,我想大家并不陌生,因为它是我们代码编写中比较常用的设计模式之一。

不过,大家可能不知道的是,单例模式还有很多别样的编写方式。

首先,先给大家说一下单例模式的几要素:

1.定义一个自己私有的对象;

2.定义一个私有的构造函数,使得外接不可以直接拿到对象本身;

3.定义一个公共的静态方法,用于返回私有对象;

4.只有在私有对象为空的时候才去new一次对象;


然后,给大家分享下三种类型的单例模式:懒汉式,饿汉式以及登记式,这三种模式是对私有对象创建模式的一种分类。

1.懒汉式

所谓懒汉式,就是在需要创建对象的时候才进行创建。

(1)普通懒汉式

public class Singleton {

  private static Singleton instance;

  private Singleton () {}

  public static Singleton getInstance() {

      if (instance == null) {

           instance = new Singleton();

       }

       return instance;

    }

}

缺点:存在线程不安全性。在多线程环境下,如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。

(2)线程安全的懒汉式

a.无关对象锁

public class Singleton {

  private static Singleton instance;

  private static Object syncLock = new Object();

  private Singleton () {}

  public static Singleton getInstance() {

    synchronize(syncLock) {

         if (instance == null) {

              instance = new Singleton();

           }

          return instance;

        }

    }

}

b.当前对象锁

public class Singleton {

  private static Singleton instance;

  private Singleton () {}

  public static Singleton getInstance() {

    synchronize(this) {

         if (instance == null) {

              instance = new Singleton();

           }

          return instance;

       }

    }

}

c.类本身锁

public class Singleton {

  private static Singleton instance;

  private Singleton () {}

  public static Singleton getInstance() {

     if (instance == null) {

        synchronize(Singleton.class) {

             if (instance == null) {

                  instance = new Singleton();

               }

              return instance;

            }

        }

    }

}

说明:如上写了a b c三种线程锁的方式,目的在于告诉大家,b方式的线程锁在单例模式中是不可取的,原因是getInstance方法是一个静态方法,在它的内部不能使用未静态的或者未实例化的类对象(避免空指针异常);

缺点:线程安全的懒汉式单例执行效率不如饿汉式

(3)内部类形式的懒汉式

public class Singleton {

  private Singleton () {}

  public static Singleton getInstance() {

       return Holder.SINGLETON ;

    }

    private static class Holder {

        private static final Singleton SINGLETON = new Singleton();

    }

}

说明:这种方式解决了上述的两种缺点,并优于饿汉式的空间换时间方案。

2.饿汉式

所谓饿汉式,就是类一编译及创建好私有对象。

public class Singleton {

  private static Singleton instance = new Singleton();

  private Singleton () {}

  public static Singleton getInstance() {

       return instance;

    }

}

缺点:类一编译即占用一定的内存存储对象,不过效率优于线程安全的懒汉式单例。典型的空间换时间方案。

3.登记式

所谓登记式,就是将私有对象存放在特定的堆栈中,用于单例对象的分组,目前我还没发现使用的环境是啥,欢迎提出指导意见。

//采用Map配置多个单例  

public class Singleton {  

    // 设立静态变量,直接创建实例  

    private static Map map = new HashMap();  

    // -----受保护的-----构造函数,不能是私有的,但是这样子类可以直接访问构造方法了  

    //解决方式是把你的单例类放到一个外在的包中,以便在其它包中的类(包括缺省的包)无法实例化一个单例类。  

    protected Singleton() {  

        System.out.println("-->私有化构造函数被调用,创建实例中");  

    }  

    // 开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  

    public static Singleton getInstance(String name) {  

        if (name == null) {  

            name = Singleton.class.getName();  

            System.out.println("-->name不存在,name赋值等于"+MySingleton3.class.getName());  

        }  

        if (map.get(name) == null) {  

            try {  

                System.out.println("-->name对应的值不存在,开始创建");  

                map.put(name, (MySingleton3)Class.forName(name).newInstance());  

            } catch (InstantiationException e) {  

                e.printStackTrace();  

            } catch (IllegalAccessException e) {  

                e.printStackTrace();  

            } catch (ClassNotFoundException e) {  

                e.printStackTrace();  

            }  

        } else {  

            System.out.println("-->name对应的值存在");  

        }  

        System.out.println("-->返回name对应的值");  

        return map.get(name);  

    }  

    public Map getMap() {  

        return map;  

    }

}

上一篇 下一篇

猜你喜欢

热点阅读