设计模式之单件模式

单件模式:确保一个类只有一个实例,并提供全局访问点。

  这一站我们来到了单件模式(Singleton Pattern):用来创建独一无二的,只有一个实例的对象的入场券。告诉大家一个好消息,单件模式的类图算是所有设计模式的类图中最简单的,事实上,它的类图上只有一个类!但是,可不要兴奋过头,尽管从类设计的视角来说它很简单,但是实现上还是会遇到相当多的波折。所以,系好安全带,我们出发咯!

  如何创建一个对象?

  new MyObject();

  万一另一个对象想创建MyObject()会怎样?可以再次new MyObject吗?

  是的,当然可以。

  所以,一旦有一个类,我们是否都能够多次地实例化它?

  如果是公开的类,就可以。

  如果不是的话,会怎样?

  如果不是公开类,只有同一个包内的类可以实例化它,但是仍可以实例化它多次。

  嗯!有意思!你知道的可以这样做吗?

public MyClass {
    
    private MyClass() {}

}

  我没想过。但是,这是合法的定义,有一定的道理。

  怎么说呢?

  我认为含有私有的构造器的类不能被实例化。

  有可以使用私有的构造器的对象吗?

  嗯,我想MyClass内的代码是唯一能调用此结构的代码。但是这有不太合乎常理。

  为什么?

  因为必须有MyClass类的实例才能调用MyClass构造器,但是因为没有其他类能够实例化MyClass,所以我们得不到这样的实例。这是“鸡生蛋,蛋生鸡”的问题。我可以在MyClass类型的对象上使用MyClass构造器,但是在这之前,必须有一个MyClass实例。在产生MyClass实例之前,又必须在MyClass实例内才能调用私有的构造器......

  嗯!我有个想法。你认为这样如何?

public MyClass {
    
    public static MyClass getInstance() {
    }

}    

  MyClass有一个静态方法。我们可以这样调用这个方法:MyClass.getInstance();

  为何调用的时候以MyClass的类名,而不是对象名?

  因为getInstance()是一个静态方法,换句话说,是一个“类”方法,你需要使用类名。

  有意思。假如把这些合在一起“是否”就可以初始化一个MyClass?

  

public MyClass {
    
    private MyClass() {}
    
    public static MyClass getInstance() {
          return new MyClass()
    } 
    
}

  当然可以。

  好了,你能想出第二种实例化对象的方式吗?

  MyClass.getInstance();

  你能完成代码使MyClass只有一个实例被产生吗?

   嗯,大概可以吧......

public class Singleton {//把MyClass改名为Singleton
    private static Singleton uniqueInstance;//利用一个静态变量来记录Singleton类的唯一实例
        //这里是其他的实例化变量
    private Singleton() {}//把构造器声明为私有化,只有Singleton类内才可以调用构造器
    public static Singleton getInstance(){//用getInstance()方法实例化对象,并返回这个实例
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
      //这里是其他的方法  
}

  我们来看看单件模式的类图吧!

  

  我们遇到麻烦了!遭遇到多线程的时候竟然能够完成两个实例化。

  没关系,我们还有办法!利用synchronized关键字可以解决多线程冲突问题。

public class Singleton {
    private static Singleton uniqueInstance;
    private Singleton() {}
    public static synchronized Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

   但是似乎同步getInstance()的做法将拖垮性能。

   1.如果getInstance()的性能对应用程序不是很关键,就什么都不要做。没错你的应用程序如果能够接受额外的负担,就忘记这件事吧。同步getInstance()的方法既简单又有效。但是你必须知道,同步一个方法可能造成程序执行效率下降100倍。因此,如果getInstance()使用频繁的话,就需要考虑其他方法了

  2.使用“急切”创建实例,而不用延迟实例化的做法

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();//急切实例化,保证了多线程安全。
    
    private Singleton() {}
    
    public static Singleton getInstance(){
        return uniqueInstance;//已经有实例了,直接返回
    }
}

  3.用“双重检查加锁”,在getInstance()中减少使用同步

  

public class Singleton {
    private volatile static Singleton uniqueInstance;
    //volatile关键字确保:当 uniqueInstance变量被初始化 Singleton实例时,
    //多线程正确地处理 uniqueInstance变量
    
    private Singleton() {}
    
    public static Singleton getInstance(){
        if(uniqueInstance == null){//注意只有第一次才彻底执行下面全部的代码
            synchronize(Singleton.class){
                if(uniqueInstance == null){//进入区块之后,如果仍是null,则创建实例
                uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

  上面这个做法可以帮你大大地减少getInstance()的时间消耗.

wǒ bú xìn nǐ huì zhè mē wú liáo dē bǎ wǒ zhè jù huà dú yí biàn . rú guǒ nǐ zhēn dē dú lē . wǒ zhǐ xiǎng gào sù ni . wǒ xǐ huan ni.

原文地址:https://www.cnblogs.com/zpfbuaa/p/5510141.html