單例模式是眾多設計模式中的一種,那說到設計模式,我們要想知道什么是設計模式?設計模式就是一套反復使用、多數人知曉的、經過分類、代碼設計經驗總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解,保證代碼的可靠性。毫無疑問,設計模式已經已經于他人系統都是多贏的;設計模式是代碼編程真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。
其實簡單來說,設計模式就是一種解決問題的思想,打個比方來說,我們想要蓋一棟歐美風格的大樓,第一次蓋,不是很懂,只能仿照歐美風格的大樓的樣子去一點一點設計,一點一點完善,哪里出了問題,在設定方案,去一點一點的修改,終拿出一個好的方法來,而這個時候我們就將問題記錄下來,包括如何去設計的這棟歐式風格的大樓。
如果后續還想要蓋一棟歐式風格的大樓,我們是不是就不用在自己去一點一點摸索了?我們只需要拿出上一次人家蓋大樓的設計方案,這樣我們就可以避免了很多問題,因為在蓋一棟大樓上面出現任何的問題都是致命的,而且造價也是很高的,所以我們就拿人家做好的解決方案來用,這也就是生活中就簡單的,直白的設計模式的解釋。
其實設計模式在我們現實生活中有很多,比如說我們去飯店吃飯,點了一個湯,服務員把湯端上來,我們直白的解決方案就是向服務員要喝湯的勺子,對吧?因為這個是解決我們不能將湯喝到嘴里簡單有效的方式,還有很多的例子,在這里就不一一的列舉了,那我們就說一下我們編程語言中的設計模式,同樣,我們編程語言中的設計模式也是用來解決我們編程過程當中的一些問題,它不僅僅是能解決Java問題,所有的面相對象的語言都可以用我們的設計模式來解決問題,設計模式總共有20多種,分別用來解決不同的問題,同樣我們今天要介紹的單例設計模式也是用來解決問題的,那它是用來解決什么問題呢?我們先從一個例子去入手看一下。
首先我創建一個Singleton類,里面只有定義了一個num屬性。
class Singleton {
int num;
}
現在我要實例化兩個Singleton類的對象,想做一件事,就是我ASingleton對象的num改變,想讓BSingleton對象的num也隨之改變,就是想讓他們兩個相互知道,一個改變了num另一個要知道。該如何去實現呢?有人說將num設置為靜態,其實是可以解決這個問題的,但是設置為靜態會有什么樣的 小問題呢?就是我們的變量聲明周期過長,如果數據量大呢?那么是不是就全部都要設置為靜態,是不是不太合理?那么這個問題該怎么解決呢?
這個時候就用到了我們的單例模式,從名字上去理解,單個實例,對嘛,如果我們能保證這兩個對象操作的是同一個實例,是不是就保證了它倆操作的都是同一個num?對的,就是這樣,那么我們如何去保證對象的唯一性呢?首先我們要想,我們通過什么來創建對象呢?構造器吧?是的,那我們是不是不能讓外部隨意的去創建對象,如果還是能隨便的創建,那我們怎么才能保證對象唯一性呢,怎么辦呢?咱們想,如果我們將構造器私有化了,是不是外部就不能隨意的去創建了?對嘛,外部都不能訪問到你的構造器,它怎么去創建你的對象呢,是的,就是這樣,那我們將構造函數私有化了,無法創建對象了也不行啊,是吧,那我們如何去操作數據呢?按照封裝的思想,外部不能訪問了,我內部去創建自身的對象可以不?我內部創建好一個自身的對象,在向外將我創建好的對象提供出去是不是就可以了,好了,基本的原理就是這樣,接下來我將問題總結一下。
如何保證對象的唯一性:
1. 不允許其他程序用new 構造器 來創建該類的對象;
2. 在該類創建一個本類實例;
3. 對外提供一個方法讓其他程序可以獲取該對象。
步奏:
1. 私有化該類的構造函數;
2. 通過new 構造器 在本類當中創建一個本類的對象;
3. 定義一個共有的方法,將創建的對象返回出去。
這就是我們的基本步奏,下面我們在程序中去演示一下:
class Singleton {
int num;
private Singleton(){} //第一步:構造函數私有化
private static Singleton s = new Singleton(); //第二步:在本類中實例化該類的實例
public static Singleton getInstance(){ //第三步:向外提供一個方法,將創建好的該類實例返回出去
return s;
}
}
通過測試類看一下效果:
public static void main(String[] args) {
Singleton sing1 = Singleton.getInstance();
Singleton sing2 = Singleton.getInstance();
sing1.num = 10;
sing2.num = 20;
System.out.println("sing2.num="+sing1.num);
System.out.println("sing2.num="+sing2.num);
}
結果:
sing1.num=20
sing2.num=20
從結果我們就能看到,當后一次sing2改變了num,同時sing1的num也隨之改變了,解釋一下為什么要將第三步的方法設置為static,因為外部無法創建我們這個類的對象,所以我們將其提升為類級別,通過類名調用,當然static也有自己的規則,所以第二步也設置為了static,而前面加上private是我們的封裝思想,同時我們可以在第三步中加入參數,做一個可控的判斷,如果滿足條件了我們才將實例給你用,不滿足條件不給你用。
這個就是單例模式的基本用法。