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

来源:https://www.cnblogs.com/xuwujing/archive/2018/07/07/9277266.html
-Advertisement-
Play Games

本篇文章主要介紹設計模式中的單例模式使用。有經典餓漢式和飽漢式,也包含最優的單例模式的介紹使用。 ...


前言

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

設計模式簡介

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

什麼是設計模式

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

為什麼使用設計模式

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

設計模式類型

設計模式有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)的方法得到該實例;

原創不易,如果感覺不錯,希望給個推薦!您的支持是我寫作的最大動力!
版權聲明:
作者:虛無境
博客園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm    
個人博客出處:http://www.panchengming.com


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現在靜態資源更新多少通過改版本號整個文件更新, 對於體積較大且經常更新的資源來說, 用戶訪問時經常需要重新下載, 使得可交互時間變長, 流量浪費, 體驗不佳. 事實上, 一個資源的更新並非整個資源都更新了, 只是其中的一小部分更新了. 基於此, 將更新的部分已補丁的形式加入到原來的文件, 通過計算... ...
  • 塊級元素居中問題 定寬塊級元素水平居中 不定寬塊級元素水平居中 不定寬塊級元素水平居中 不定寬塊級元素水平居中 ... ...
  • 第一節:什麼是ES6? ES6是什麼?跟JavaScript有什麼關係? JavaScrip由三部分組成:分別是ECMAScript,BOM和DOM. 1)由此看出,ECMAScript是JavaScript的組成部分,是JS的核心,描述了語言的基本語法(var、for、if、array等)和數據類 ...
  • 全局變數和局部變數 1 var a=1; //全局變數 2 function fun() { 3 var a=2; //局部變數 4 b=1; //全局變數 5 alert(a); //2 6 } 7 alert(a); //1 8 alert(b); //1 JS中函數內是可以直接讀取全局變數,而 ...
  • 網站首頁導航 ...
  • 基於React的一個簡單Todo-list 先賭為快:線上DEMO,感覺還不錯點一下star -_- ~ 源碼地址: 一、已經完成的功能 1、新增選項(預設未完成) 2、完成狀態可以切換 3、當前選項可以刪除 4、全部選項選中狀態切換 5、全部個數,完成個數,未完成個數實時讀取 6、刷新狀態不變 7 ...
  • 1. 使用Set ES6 提供了新的數據結構Set, 它類似數組,和C++中的set容器一樣,它成員的值都是唯一的,沒有重覆的值;Set本身是一個構造函數,用來生成Set數據結構。 還有更簡單的方式 上面這種方式在於Array.from方法可以將Set結構轉化為數組。如果你還覺得不過癮,那麼還有一種 ...
  • HTML5 標準事件 oninput 和 IE 專屬事件 onpropertychange 事件實時監聽input輸入框value的變化 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...