大話設計模式(1)——單例模式

設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。**使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。**設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石同樣。只有精通了設計模式,纔敢說真正理解了軟件工程。能夠說,設計模式是每個架構師所必備的技能之一。html

PS:雖然本文代碼是基於Java(但學習設計模式不拘泥於設計模式,不論是何種面嚮對象語言,甚至是非OO語言,我以爲都能從設計模式中窺探一絲代碼架構的奧祕),主要來源於《Head First 設計模式》這本書,並附上了詳細的代碼,強烈建議你們仔細閱讀源代碼。git

在本文中不會列出所有的代碼,重點集中在解釋什麼是設計模式?什麼場景下能夠用這種設計模式?嘗試以實際的問題來驅動學習,使得咱們對設計模式的理解更爲深入而具體。github

讓咱們一塊兒來學習設計模式吧!編程

前言

關於面向對象特性,在《大話設計模式》中有一段極其生動的講解,面向對象就得像活字印刷術同樣:設計模式

img

第一,要改,只需更改要改之字,此爲可維護;第二,這些字並不是用完此次就無用,徹底能夠在後來的印刷中重複使用,此乃可複用;第三,此詩若要加字,只需另刻字加入便可,這是可擴展;第四,字的排列其實多是豎排多是橫排,此時只需將活字移動就可作到知足排列需求,此是靈活性好安全

設計原則

想要精通設計模式,必需要先搞清楚設計模式的設計原則。markdown

  • 找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒!——也能夠說類應該對擴展開放,對修改關閉,簡稱開放封閉原則

PS:怎麼看什麼是「變化」?——若是每次需求一來,某個部分就必須改變,那麼就是不穩定變化的代碼。架構

  • 針對接口編程,而不是針對實現編程。——也能夠說要依賴抽象,不要依賴具體類,簡稱依賴倒置原則

PS:針對接口編程,實際上是」面向超類型(抽象類、接口)「編程。這個原則讓編程的細節被隱藏,不會由於修改具體實現而常常改動程序結構。函數

  • 多用組合,少用繼承。

PS:雖然繼承接口可讓不一樣子類中實現方式不一樣,可是接口不具備複用性(每個接口的實現代碼都得重寫),而組合卻能夠爲後續的程序設計提供便利。oop

這個能夠看看:www.huaweicloud.com/articles/d5…

  • 爲了交互對象之間的鬆耦合設計而努力

PS:交互對象之間應儘量的鬆耦合,以應對後期項目業務邏輯變更的風險。

  • 一個類對本身依賴的類知道的越少越好,簡稱最少知識原則。(亦稱得墨特爾法則)

PS:一旦某個類應該只與它必須知道的類去交互,而不該該知道其餘的類,編程的總原則就是高聚合,低耦合。

  • 一個類應該只有一個引發變化的緣由,單一職責原則。

PS:不該該存在多於一個致使類變動的緣由,如若否則,就應該將類拆分。

UML類圖

爲了在以後的學習中更好地理解設計模式,咱們須要先學習一下如何繪製、閱讀UML類圖。

爲了更好地理解這本書的例子,須要先對UNL類圖進行簡單的學習。大部分的關係都在下面這幅圖裏面了,多看並記憶便可:

img

對於類中字段和方法:+ 表示public;-表示private;#表示protected

繼承關係用空心三角加實線

接口關係用空心三角加虛線

關聯關係(如上圖企鵝和睦候,企鵝須要瞭解氣候用實線箭頭

PS:關聯能夠當作是,某個類中含有其餘某類的對象。

聚合關係(大雁和雁羣,是一種弱擁有關係)用空心菱形和實線箭頭

合成(組合)關係(鳥和翅膀是強擁有,即總體和局部的關係)用實心菱形和實線箭頭,兩端的底下的數字,表示幾對幾的關係;

依賴關係(某個類須要基於某個類而存在)用虛線箭頭

繪製UML類圖,可使用Visio或者Drawio

設計原則是編程設計過程當中須要時刻考慮的,近乎於道,這些設計原則的組合、碰撞,就產生了許多精彩絕倫、可用性極強的設計模式,是能夠用的術。之因此稱爲模式,是由於在平常的編程開發中,咱們均可以學習、借鑑它們。接下來對設計模式的介紹,我會從:定義、場景、解決的方式方便你們的理解。

單例模式

定義

單例模式確保一個類只有一個實例,並提供一個全局訪問點

這定義已經很明確了,那就是全局只能有這個類的一個實例

場景

單例模式能夠說你們都有所耳聞,甚至實際開發中也用到過(Spring中的組件Bean就是一個一個的單例),當你須要控制某個類的實例數量時,就須要使用單例模式了

解決

那麼如何讓全局只有一個類呢?

——簡單,將構造函數聲明爲private,這樣就不能在外部經過new來實現了。

問題來了,既然構造函數已經被聲明爲private,怎麼得到該類的對象呢?

——簡單,在該類的內部聲明一個靜態成員函數便可。

img

單例模式的實現分爲懶漢、餓漢模式。

餓漢模式:類初始化的時候就創建該類的一個實例:

public class SingleObject {
 
   //建立 SingleObject 的一個對象
   private static SingleObject instance = new SingleObject();
 
   //讓構造函數爲 private,這樣該類就不會被實例化
   private SingleObject(){}
 
   //能夠經過該API獲取惟一可用的對象
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}
複製代碼

懶漢模式:知道其餘類須要該實例的時候才建立對應的實例:

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
		//須要的時候再建立對應的實例
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}
複製代碼

考慮到線程安全,能夠改成:

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
		//採用雙檢查鎖,避免頻繁加鎖,性能較好
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}
複製代碼

**思考:**單例模式除了能夠保證惟一的實例外,還有什麼好處呢?

——單例模式由於Singleton類封裝它的惟一實例,這樣它能夠嚴格地控制客戶怎樣訪問它以及什麼時候訪問它簡單地說就是對惟一實例的受控訪問

項目地址

github.com/white0dew/D…

參考資料

《大話設計模式》

《Headfist 設計模式》

相關文章
相關標籤/搜索