1. 程式人生 > >Java進階篇設計模式之一 ----- 單例模式

Java進階篇設計模式之一 ----- 單例模式

前言

在剛學程式設計沒多久就聽說過設計模式的大名,不過由於當時還是個徹徹底底的菜鳥,並沒有去觸碰。直到在開始工作中對簡單的業務程式碼較為熟悉之後,才正式的接觸設計模式。當時最早接觸的設計模式是工廠模式,不過本文講的是單例模式,這裡就留著下篇文章中在講解。至於為什麼先講解單例模式? 那是因為單例模式是設計模式中最簡單的... 。凡事總有個先後順序,所以就先易後難了。好了,廢話不多說了,開始進入正片。

設計模式簡介

說明:這裡說了的簡介就是真的 “簡介”。

什麼是設計模式

設計模式是一套被反覆使用的、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。

為什麼使用設計模式

使用設計模式是為了重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。

設計模式型別

設計模式有23種類型。按照主要分類可以分為三大類:

一、建立型模式

這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。

  • 單例模式
  • 工廠模式
  • 抽象工廠模式
  • 建造者模式
  • 原型模式

二、結構型模式

這些設計模式關注類和物件的組合。繼承的概念被用來組合介面和定義組合物件獲得新功能的方式。

  • 介面卡模式
  • 橋接模式
  • 過濾器模式
  • 組合模式
  • 裝飾器模式
  • 外觀模式
  • 享元模式
  • 代理模式

三、行為型模式

這些設計模式特別關注物件之間的通訊。

  • 責任鏈模式
  • 命令模式
  • 直譯器模式
  • 迭代器模式
  • 中介者模式
  • 備忘錄模式
  • 觀察者模式
  • 狀態模式
  • 空物件模式
  • 策略模式
  • 模板模式
  • 訪問者模式

設計模式的原則

設計模式的六大原則

  1. 開閉原則:對擴充套件開放,對修改關閉。
  2. 里氏代換原則:對開閉原則的補充。任何基類可以出現的地方,子類一定可以出現。LSP 是繼承複用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被複用,而派生類也能夠在基類的基礎上增加新的行為。
  3. 依賴倒轉原則:針對介面程式設計,依賴於抽象而不依賴於具體。
  4. 介面隔離原則:儘量使用多個隔離的介面,為了降低類之間的耦合度。
  5. 迪米特法則:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模組相對獨立。
  6. 合成複用原則:儘量使用合成/聚合的方式,而不是使用繼承。

單例模式

什麼是單例模式

保證一個系統中的某個類只有一個例項而且該例項易於外界訪問。例如Windows介面的工作管理員就可以看做是一個單例。

單例模式的使用場景

在程式中比較常用的是資料庫連線池執行緒池日誌物件等等。

單例模式使用

最早我們在學習單例模式的時候,基本都會接觸這兩種模式:餓漢式和飽漢式(懶漢式)。
那我們先來看看這兩個模式的實現。

餓漢式
定義一個私有的構造方法,並將自身的例項物件設定為一個私有屬性,並加上static和final修飾符,然後通過公共的靜態方法呼叫返回例項。

 class SingletonTest1 {  

    private SingletonTest1() {  
    }  
    private static final SingletonTest1 instance = new SingletonTest1();  

    public static SingletonTest1 getInstance() {  
        return instance;  
    }  
}

飽漢式
定義一個私有的構造方法,定義一個該類靜態私有的變數,然後定義一個公共的靜態方法,對該類的值進行空判斷,不為空直接返回,否則重新構建一個。

class SingletonTest2 {

     private SingletonTest2() {   
     }   

     private static SingletonTest2 instance;   

     public static SingletonTest2 getInstance() {   
         if (instance == null) {
            instance = new SingletonTest2();
        }   
         return instance;   
     }   
 }  

簡單的介紹了這兩種的模式,然後我們再來看看這兩種模式的優缺點吧。
餓漢式

  • 優點:寫起來很簡單,並且不會因為不加synchronized關鍵字而造成的執行緒不安全問題。
  • 缺點:當該類被載入的時候,會初始化該例項和靜態變數並被建立並分配記憶體空間,並且會一直佔用記憶體。

飽漢式

  • 優點:寫起來很簡單,在第一次呼叫的時候才會初始化,節省了記憶體。
  • 缺點:執行緒不安全,多個執行緒呼叫可能會出現多個例項。
  • 總結:書寫簡單,執行緒不安全,效率還行。

雖然 飽漢式可以通過加上synchronized關鍵字保證執行緒安全。但是效率方法來說還不說是最優。

這裡在介紹下個人認為在JDK1.5之前最優的兩種寫法,一種是靜態內部類,另一種是雙重鎖檢查

靜態內部類
定義一個私有的構造方法,定義一個該類私有靜態的內部類,然後在內部類中定義一個該類的靜態變數,然後通過公共的final修飾的靜態方法呼叫返回例項。

  class  SingletonTest4 {
      private SingletonTest4(){
        }
       private static class SingletonTest5{
           private static SingletonTest4 instance = new SingletonTest4();
        }
        public static final SingletonTest4 getInstance(){
            return SingletonTest5.instance;
        }
   }

因為該類的內部類是私有的,除了對外公佈的公共靜態方法getInstance(),是無法訪問的。因為它是延遲載入,所以讀取讀取例項的時候不會進行同步,幾乎沒有效能的缺陷,而且還是執行緒安全的,並且不依賴JDK的版本。

雙重鎖檢查
定義一個私有構造方法,通過volatile定義靜態私有變數,保證了該變數的可見性,然後定義一個共有的靜態方法,第一次對該物件例項化時與否判斷,不為空直接返回,提升效率;然後使用synchronized 進行同步程式碼塊,防止物件未初始化時,在多執行緒訪問該物件在第一次建立後,再次重複的被建立;然後第二次對該物件例項化時與否判斷,如果未初始化,則初始化,否則直接返回該例項。

  class SingletonTest6 { 
        private SingletonTest6() { 
        }   
        private static volatile SingletonTest6 instance;  
        public static SingletonTest6 getIstance() { 
            if (instance == null) {
                synchronized (SingletonTest6.class) {
                    if (instance == null) {
                        instance = new SingletonTest6();   
                    }   
                }   
            }   
            return instance;   
        }   
    }  

這種模式在很長的一段時間內可以說是最優的了,記憶體佔用低,效率高,執行緒安全,多執行緒操作原子性。但是有個缺點就是書寫麻煩,對新手不太友好。

JDK1.5之後出現了列舉,並且完美支援單例模式,並且執行緒安全、效率高!但是這些不是最重要的,最重要的是書寫超級簡單!究竟有多簡單,看下面的示例應該就可以瞭解一下了。。。

列舉單例

 enum SingletonTest7{
        INSTANCE;
     }

對的,你沒看錯,就這點程式碼,其它不需要了。。。
列舉需要在JDK1.5之後的版本,它無償提供序列化機制,絕對防止多次例項化,即使在面對複雜的序列化或者反射攻擊的時候。這種方法也被Effective Java作者Josh Bloch 所提倡。

總結

單例模式的幾種使用就到這了,那麼我們來總結下使用單例模式需要注意什麼(不包括列舉)。

  1. 構造方法私有化(private);
  2. 定義一個私有(private)靜態(static)例項化物件;
  3. 對外提供一個公共(public)靜態(static)的方法得到該例項;

相關推薦

Java設計模式之一 ----- 模式

前言 在剛學程式設計沒多久就聽說過設計模式的大名,不過由於當時還是個徹徹底底的菜鳥,並沒有去觸碰。直到在開始工作中對簡單的業務程式碼較為熟悉之後,才正式的接觸設計模式。當時最早接觸的設計模式是工廠模式,不過本文講的是單例模式,這裡就留著下篇文章中在講解。至於為什麼先講解單例模式? 那是因為單例模式是設計模式中

Java設計模式之二 ----- 工廠模式

class computer 社會 進階 輕松 override out 是否 return 前言 在上一篇中我們學習了單例模式,介紹了單例模式創建的幾種方法以及最優的方法。本篇則介紹設計模式中的工廠模式,主要分為簡單工廠模式、工廠方法和抽象工廠模式。 簡單工廠模式 簡單

Java設計模式之四 -----適配器模式和橋接模式

原則 pub 是我 protect 接口 logs 將不 多說 外鏈 前言 在上一篇中我們學習了創建型模式的建造者模式和原型模式。本篇則來學習下結構型模式的適配器模式和橋接模式。 適配器模式 簡介 適配器模式是作為兩個不兼容的接口之間的橋梁。這種類型的設計模式屬於結構型模

Java設計模式之五-----外觀模式和裝飾器模式

和我 logs 適配器模式 del xtra implement () 實例化 網絡遊戲 前言 在上一篇中我們學習了結構型模式的適配器模式和橋接模式。本篇則來學習下結構型模式的外觀模式和裝飾器模式。 外觀模式 簡介 外觀模式隱藏系統的復雜性,並向客戶端提供了一個客戶端可以

Java設計模式之六 ----- 組合模式和過濾器模式

對組 www. 希望 als oid block 個人 定義 lsi 前言 在上一篇中我們學習了結構型模式的外觀模式和裝飾器模式。本篇則來學習下組合模式和過濾器模式。 組合模式 簡介 組合模式是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表

Java設計模式之八 ----- 責任鏈模式和命令模式

如果能 clean branch pcm tle 開始 類型 mar www 前言 在上一篇中我們學習了結構型模式的享元模式和代理模式。本篇則來學習下行為型模式的兩個模式, 責任鏈模式(Chain of Responsibility Pattern)和命令模式(Comman

Java設計模式之九----- 解釋器模式和叠代器模式

簡單 目的 java進階 使用 記錄 ace 客戶端 -- pro 前言 在上一篇中我們學習了行為型模式的責任鏈模式(Chain of Responsibility Pattern)和命令模式(Command Pattern)。本篇則來學習下行為型模式的兩個模式, 解釋器模

Java設計模式之十 ---- 訪問者模式和中介者模式

前言 在上一篇中我們學習了結構型模式的直譯器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern)。本篇則來學習下行為型模式的兩個模式,訪問者模式(Visitor Pattern)和中介者模式(Mediator Pattern)。 訪問者模式 簡介 訪問者

Java設計模式之十一 ---- 策略模式和模板方法模式

前言 在上一篇中我們學習了行為型模式的訪問者模式(Visitor Pattern)和中介者模式(Mediator Pattern)。本篇則來學習下行為型模式的兩個模式,策略模式(Strategy Pattern)和模板模式(Mediator Pattern)。 策略模式 簡介 策略模式(Stra

Java設計模式之十二 ---- 備忘錄模式和狀態模式

前言 在上一篇中我們學習了行為型模式的策略模式(Strategy Pattern)和模板模式(Template Pattern)。本篇則來學習下行為型模式的兩個模式,備忘錄模式(Memento Pattern)和狀態模式(Memento Pattern)。 備忘錄模式 簡介 備忘錄模式(Meme

Java設計模式之七 ----- 享元模式和代理模式

前言 在上一篇中我們學習了結構型模式的組合模式和過濾器模式。本篇則來學習下結構型模式最後的兩個模式, 享元模式和代理模式。 享元模式 簡介 享元模式主要用於減少建立物件的數量,以減少記憶體佔用和提高效能。這種型別的設計模式屬於結構型模式,它提供了減少物件數量從而改善應用所需的物件結構的方式。 用通俗的話來

Java 設計模式之十四 ----- 總結

前言 本篇是講述之前學習設計模式的一個總結篇,其目的是為了對這些設計模式的進行一個提煉總結,能夠通過檢視看此篇就可以理解一些設計模式的核心思想。 設計模式簡介 什麼是設計模式 設計模式是一套被反覆使用的、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。 為什麼使用設計模式 使用

Java設計模式之九----- 直譯器模式和迭代器模式

前言 在上一篇中我們學習了行為型模式的責任鏈模式(Chain of Responsibility Pattern)和命令模式(Command Pattern)。本篇則來學習下行為型模式的兩個模式, 直譯器模式(Interpreter Pattern)和迭代器模式

Java設計模式之四 -----介面卡模式和橋接模式

前言 在上一篇中我們學習了建立型模式的建造者模式和原型模式。本篇則來學習下結構型模式的介面卡模式和橋接模式。 介面卡模式 簡介 介面卡模式是作為兩個不相容的介面之間的橋樑。這種型別的設計模式屬於結構型模式,它結合了兩個獨立介面的功能。 簡單的來說就是通過某個介面將不相容的兩個類進行相容,俗稱轉換器。 生活

Java設計模式之三 ----- 建造者模式和原型模式

前言 在上一篇中我們學習了工廠模式,介紹了簡單工廠模式、工廠方法和抽象工廠模式。本篇則介紹設計模式中屬於建立型模式的建造者模式和原型模式。 建造者模式 簡介 建造者模式是屬於建立型模式。建造者模式使用多個簡單的物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式

C#設計模式之一模式(Singleton Pattern)【創建型】

nal 設計 類庫 開發 避免 sum behavior 並且 負責 原文:C#設計模式之一單例模式(Singleton Pattern)【創建型】一、引言 看了李建忠老師的講的設計模式已經有一段時間了(這段時間大概有一年多了),自己還沒有寫過自己的、有關設計模

python設計模式之一-模式

引言 在面向物件的世界裡,物件是對客觀事物的抽象,類是對物件的抽象。它們之間的關係是,物件是類的例項,類是物件的模板。 這段文字表述起來費勁,理解起來也費勁,還是講生活中的例子吧。比如說“大河”,一聯想到這個詞,不同的人腦海中的印象是不一樣的,有的是“大漠孤煙直,長河落日圓”,有的是“春江潮水連海平,海上

設計模式之一----模式

在一個系統裡,對於某些物件,有且只能有一個,當我們有這樣的需求的時候,就需要用到單例模式了。 單例模式分為懶漢模式和餓漢模式。我們使用程式碼來進行說明: 首先建立一個用到了餓漢模式的Singleton類在com.single下: package com.single; /*

設計模式之一模式

目錄結構 前言 接下來的系列文章我們會談設計模式,設計模式不僅僅存在Java開發語言中,而是遍及軟體領域且至關重要,是前輩開發總結的經驗,一種設計思想,一種架構;在軟體開發中,唯一不變的就是需求的變化,開發人員不僅要滿足當下的功能需求,還要考慮對後續可能的變化,設計的系統就應有良好的拓展性。在公司接手上一

大型Java專題(五) 設計模式模式與原型模式

## 前言 ​ 今天開始我們專題的第四課了,最近公司專案忙,沒時間寫,今天抽空繼續。上篇文章對工廠模式進行了詳細的講解,想必大家對設計模式合理運用的好處深有感觸。本章節將介紹:單例模式與原型模式。本章節參考資料書籍《Spring 5核心原理》中的第一篇 Spring 內功心法(Spring中常用的設計模式)