在前面的博文中,小編介紹了設計模式中的原型模式,不知道有沒有幫助到有需要的小夥伴呢`(*∩_∩*)′,今天這篇博文,小編繼續來介紹相關的設計模式,今天要和大家見面的是單例模式,不由得又讓小編想起Darry Ring,或許只能想想而已`(*∩_∩*)′,開篇閒扯到這裏,接着步入正題,今天這篇博文,小編會從什麼是單例模式,爲什麼要使用單例模式,餓漢式,懶漢式、雙重檢查以及配之以相關的Demo進行講解,希望對有需要的小夥伴有幫助,還請小夥伴多多指教。
什麼是單例模式
單例模式是一種對象創建型模式,使用單例模式,可以保證爲一個類只生成唯一實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象,其實GOF對單例模式的定義是:保證一個類, 只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法,我們來看一下單例模式的結構圖:
爲什麼要使用單例模式
在應用系統開發中,我們常常有以下需求
a、在多個線程之間,比如servlet環境,共享同一個資源或者操作同一個對象。
b、在整個程序空間使用全局變量,共享資源。
c、大規模系統中,爲了性能的考慮,需要節省對象的創建時間等等。
因爲單例模式可以保證爲一個類只生成唯一的實例對象,所以這些情況,單例模式就派上用場了。
單例模式的實現
a、餓漢式
b、懶漢式
c、雙重檢查
首先,我們來實現一個簡單的,新建一個java項目,新建Person類,生成get和set方法,保證人只有一個實例,計劃生育,響應國家號召是不是`(*∩_∩*)′,編寫相關代碼,如下所示:
public class Person {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
新建類MainClass,我們可以new多少個對象呢?編寫相關代碼,如下所示:public class MainClass {
public static void main(String[] args){
Person per = new Person();
Person per2 = new Person();
per.setName("xiaoding");
per2.setName("dingding");
System.out.println(per.getName());
System.out.println(per2.getName());
}
}
運行,如下所示:
通過Person類,getName得到的是兩個name,表明這兩個根本就不是一個對象,也就是說,通過person類,我們生成了兩個不同的對象,如果是一個的話,她們的名字應該是一樣的,我們如何保證只有一個對象呢?我們在MainClass裏面new的是她的構造函數,改造Person的代碼,把構造函數私有化,代碼如下所示:
public class Person {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person(){
}
//提供一個全局的靜態方法
public static Person getPerson(){
return new Person();
}
}
改造MainClass的方法,如下所示:public class MainClass {
public static void main(String[] args){
Person per = Person.getPerson();
Person per2 = Person.getPerson();
per.setName("xiaoding");
per2.setName("dingding");
System.out.println(per.getName());
System.out.println(per2.getName());
}
}
運行,如下所示:
運行還是兩個對象,我們如何保證是一個對象呢?如何保證實例化一個對象呢?我們可以採用餓漢式,編寫Person的代碼部分我們直接通過對象就能調用,如下所示:
public class Person {
public static final Person person = new Person();
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person(){
}
//提供一個全局的靜態方法
public static Person getPerson(){
Return person;
}
}
運行,效果如下所示:
這個時候就表示,他們是同一個對象,getPerson的是一個對象,那麼什麼是懶漢式呢?重新新建一個了Person2,編寫相關代碼如下所示:
public class Person2 {
private String name;
private static Person2 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person2(){
}
//提供全局的靜態方法
public static Person2 getPerson(){
if(person == null){
person = new Person2();
}
return person;
}
}
運行效果如下所示:
這個呢就是所謂的餓漢式,懶漢式類加載的時候直接初始化,如果是多線程,懶漢式是不能保證只有一個實例的,那麼我們如何解決這個問題呢?新建類Person3,編寫相關代碼:
public class Person3 {
private String name;
private static Person3 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person3(){
}
//提供全局的靜態方法
public static Person3 getPerson(){
if(person == null){
person = new Person3();
}
return person;
}
}
Person3相對於Person2來說,解決了多線程的問題,接着我們來看雙重檢查,雙重檢查,我們來看新建類Person4,編寫相關代碼,如下所示:public class Person4 {
private String name;
private static Person4 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person4(){
}
//提供全局的靜態方法
public static Person4 getPerson(){
if(person == null){
synchronized(Person4.class){
if(person == null){
person = new Person4();
}
}
}
return person;
}
}
小編寄語:該博文,小編主要簡單的介紹了單利模式,分別介紹了什麼是單例模式、單例模式的結構圖、餓漢式、懶漢式、雙重檢查等方面做了簡單的介紹,對於系統中的某些類來說,只有一個實例很重要,例如,一個系統中可以存在多個打印任務,但是隻能有一個正在工作的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。如在Windows中就只能打開一個任務管理器。如果不使用機制對窗口對象進行唯一化,將彈出多個窗口,如果這些窗口顯示的內容完全一致,則是重複對象,浪費內存資源;如果這些窗口顯示的內容不一致,則意味着在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪一個纔是真實的狀態。因此有時確保系統中某個對象的唯一性即一個類只能有一個實例非常重要。如何保證一個類只有一個實例並且這個實例易於被訪問呢?定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象。一個更好的解決辦法是讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例被創建,並且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。