欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 單例模式 Singleton 簡單實例設計模式解析

 更新時間:2016年12月16日 16:12:59   投稿:lqh  
這篇文章主要介紹了單例模式 Singleton 簡單實例設計模式解析的相關資料,需要的朋友可以參考下

單例模式 Singleton 簡單實例設計模式解析

前言

今天我來全面總結一下Android開發(fā)中最常用的設計模式 - 單例模式。

關于設計模式的介紹,可以看下我之前寫的:1分鐘全面了解“設計模式”

目錄

這里寫圖片描述

1. 引入

1.1 解決的是什么問題

之前說過,設計模式 = 某類特定問題的解決方案,那么單例模式是解決什么問題的解決方案呢?

含義:單例 =一個實例;

解決的問題:降低對象之間的耦合度

解決方法:單例模式,即實現(xiàn)一個類只有一個實例化對象,并提供一個全局訪問點

1.2 實例引入

接下來我用一個實例來對單例模式進行引入

背景:小成有一個塑料生產(chǎn)廠,但里面只有一個倉庫。

目的:想用代碼來實現(xiàn)倉庫的管理

現(xiàn)有做法: 建立倉庫類和工人類

其中,倉庫類里的quantity=商品數(shù)量;工人類里有搬運方法MoveIn(int i)和MoveOut(int i)。

出現(xiàn)的問題:通過測試發(fā)現(xiàn),每次工人搬運操作都會新建一個倉庫,就是貨物都不是放在同一倉庫,這是怎么回事呢?(看下面代碼)

package scut.designmodel.SingletonPattern;


//倉庫類
class StoreHouse {
  private int quantity = 100;

  public void setQuantity(int quantity) {
    this.quantity = quantity;
  }

  public int getQuantity() {
    return quantity;
  }
}

//搬貨工人類
class Carrier{
  public StoreHouse mStoreHouse;
  public Carrier(StoreHouse storeHouse){
    mStoreHouse = storeHouse;
  }
  //搬貨進倉庫
  public void MoveIn(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
  }
  //搬貨出倉庫
  public void MoveOut(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
  }
}

//工人搬運測試
public class SinglePattern {
  public static void main(String[] args){
    StoreHouse mStoreHouse1 = new StoreHouse();
    StoreHouse mStoreHouse2 = new StoreHouse();
    Carrier Carrier1 = new Carrier(mStoreHouse1);
    Carrier Carrier2 = new Carrier(mStoreHouse2);

    System.out.println("兩個是不是同一個?");

    if(mStoreHouse1.equals(mStoreHouse2)){//這里用equals而不是用 == 符號,因為 == 符號只是比較兩個對象的地址
      System.out.println("是同一個");
    }else {
      System.out.println("不是同一個");
    }
    //搬運工搬完貨物之后出來匯報倉庫商品數(shù)量
    Carrier1.MoveIn(30);
    System.out.println("倉庫商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉庫商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

結果:

兩個是不是同一個?
不是同一個
倉庫商品余量:130
倉庫商品余量:50

2. 單例模式介紹

2.1 解決的問題(應用場景)

沖突:從上面的結果可以看出,工人類操作的明顯不是同一個倉庫實例。

目標:全部工人操作的是同一個倉庫實例

單例模式就是為了解決這類問題的解決方案:實現(xiàn)一個類只有一個實例化對象,并提供一個全局訪問點2.2 工作原理

在Java中,我們通過使用對象(類實例化后)來操作這些類,類實例化是通過它的構造方法進行的,要是想實現(xiàn)一個類只有一個實例化對象,就要對類的構造方法下功夫:
這里寫圖片描述

單例模式的一般實現(xiàn):(含使用步驟)

public class Singleton {
//1. 創(chuàng)建私有變量 ourInstance(用以記錄 Singleton 的唯一實例)
//2. 內部進行實例化
  private static Singleton ourInstance = new Singleton();

//3. 把類的構造方法私有化,不讓外部調用構造方法實例化
  private Singleton() {
  }
//4. 定義公有方法提供該類的全局唯一訪問點
//5. 外部通過調用getInstance()方法來返回唯一的實例
  public static Singleton newInstance() {
    return ourInstance;
  }
}

好了,單例模式的介紹和原理應該了解了吧?那么我們現(xiàn)在來解決上面小成出現(xiàn)的“倉庫不是一個”的問題吧!

2.3 實例介紹

小成使用單例模式改善上面例子的代碼:

package scut.designmodel.SingletonPattern;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//單例倉庫類
class StoreHouse {

  //倉庫商品數(shù)量
  private int quantity = 100;
  //自己在內部實例化
  private static StoreHouse ourInstance = new StoreHouse();;
  //讓外部通過調用getInstance()方法來返回唯一的實例。
  public static StoreHouse getInstance() {
    return ourInstance;
  }

  //封閉構造函數(shù)
  private StoreHouse() {
  }

  public void setQuantity(int quantity) {
    this.quantity = quantity;
  }

  public int getQuantity() {
    return quantity;
  }
}


//搬貨工人類
class Carrier{
  public StoreHouse mStoreHouse;
  public Carrier(StoreHouse storeHouse){
    mStoreHouse = storeHouse;
  }
  //搬貨進倉庫
  public void MoveIn(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
  }
  //搬貨出倉庫
  public void MoveOut(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
  }
}

//工人搬運測試
public class SinglePattern {
  public static void main(String[] args){
    StoreHouse mStoreHouse1 = StoreHouse.getInstance();
    StoreHouse mStoreHouse2 = StoreHouse.getInstance();
    Carrier Carrier1 = new Carrier(mStoreHouse1);
    Carrier Carrier2 = new Carrier(mStoreHouse2);

    System.out.println("兩個是不是同一個?");

    if(mStoreHouse1.equals(mStoreHouse2)){
      System.out.println("是同一個");
    }else {
      System.out.println("不是同一個");
    }
    //搬運工搬完貨物之后出來匯報倉庫商品數(shù)量
    Carrier1.MoveIn(30);
    System.out.println("倉庫商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉庫商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

結果:

兩個是不是同一個?
是同一個
倉庫商品余量:130
倉庫商品余量:80

從結果分析,使用了單例模式后,倉庫類就只有一個倉庫實例了,再也不用擔心搬運工人進錯倉庫了?。?!

2.4 優(yōu)點

  1. 提供了對唯一實例的受控訪問;
  2. 由于在系統(tǒng)內存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能;
  3. 可以根據(jù)實際情況需要,在單例模式的基礎上擴展做出雙例模式,多例模式;

2.5 缺點

  1. 單例類的職責過重,里面的代碼可能會過于復雜,在一定程度上違背了“單一職責原則”。
  2. 如果實例化的對象長時間不被利用,會被系統(tǒng)認為是垃圾而被回收,這將導致對象狀態(tài)的丟失。

3. 單例模式的實現(xiàn)方式

3.1 一般情況

餓漢式(最簡單的單例實現(xiàn)方式)

class Singleton {
  private static Singleton ourInstance = new Singleton();

  private Singleton() {
  }

  public static Singleton newInstance() {
    return ourInstance;
  }
}

應用場景:

  • 要求直接在應用啟動時加載并初始化
  • 單例對象要求初始化速度非常快且占用內存非常小

懶漢式

懶漢式與餓漢式最大的區(qū)別是單例的初始化操作的時機

  • 餓漢式:自動進行單例的初始化
  • 懶漢式:有需要的時候才手動調用newInstance()進行單例的初始化操作
class Singleton {
  private static Singleton ourInstance = null;

  private Singleton() {
  }

  public static Singleton newInstance() {
  if( ourInstance == null){
    ourInstance = new Singleton();
    }
    return ourInstance;
  }
}

應用場景:

  • 單例初始化的操作耗時比較長而應用對于啟動速度又有要求
  • 單例的占用內存比較大
  • 單例只是在某個特定場景的情況下才會被使用,即按需延遲加載單例。

3.2 多線程下的單例模式實現(xiàn)

在多線程的情況下:

  • 對于“餓漢式單例模式”:適用,因為JVM只會加載一次單例類;
  • 對于“懶漢式單例模式”:不適用,因為“懶漢式”在創(chuàng)建單例時是線程不安全的,多個線程可能會并發(fā)調用 newInstance 方法從而出現(xiàn)重復創(chuàng)建單例對象的問題。

解決方案1:同步鎖

使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入造成instance被多次實例化。

class Singleton {
  private static Singleton ourInstance = null;

  private Singleton() {
  }

  public static Singleton newInstance() {
   synchronized (Singleton.class){
     if( ourInstance == null){
      ourInstance = new Singleton();
    }
   }
    return ourInstance;
  }
}

解決方案2:雙重校驗鎖

在同步鎖的基礎上( synchronized (Singleton.class) 外)添加了一層if,這是為了在Instance已經(jīng)實例化后下次進入不必執(zhí)行 synchronized (Singleton.class) 獲取對象鎖,從而提高性能。

class Singleton {
  private static Singleton ourInstance = null;

  private Singleton() {
  }

  public static Singleton newInstance() {
if( ourInstance == null){
 synchronized (Singleton.class){
   if( ourInstance == null){
     ourInstance = new Singleton();
     }
   }
 }
    return ourInstance;
  }
}

解決方案3:靜態(tài)內部類

在JVM進行類加載的時候會保證數(shù)據(jù)是同步的,我們采用內部類實現(xiàn):在內部類里面去創(chuàng)建對象實例。
只要應用中不使用內部類 JVM 就不會去加載這個單例類,也就不會創(chuàng)建單例對象,從而實現(xiàn)“懶漢式”的延遲加載和線程安全。

class Singleton {

  //在裝載該內部類時才會去創(chuàng)建單例對象
  private static class Singleton2{
   private static Singleton ourInstance = new Singleton();
  }
  private Singleton() {
  }

  public static Singleton newInstance() {
    return Singleton2.ourInstance;
  }
}

解決方案4:枚舉類型

最簡潔、易用的單例實現(xiàn)方式,(《Effective Java》推薦)

public enum Singleton{

  //定義一個枚舉的元素,它就是Singleton的一個實例
  instance;

  public void doSomething(){
  }  

}

使用方式如下:

Singleton singleton = Singleton.instance;
singleton.doSomething();

5. 總結

本文主要對單例模式進行了全面介紹,包括原理和實現(xiàn)方式,接下來我會繼續(xù)講解其他設計模式,有興趣可以繼續(xù)關注

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關文章

  • java中HashMap的原理分析

    java中HashMap的原理分析

    HashMap在Java開發(fā)中有著非常重要的角色地位,每一個Java程序員都應該了解HashMap。詳細地闡述HashMap中的幾個概念,并深入探討HashMap的內部結構和實現(xiàn)細節(jié),討論HashMap的性能問題
    2016-03-03
  • 更改Maven軟件源為阿里云源的方法詳解

    更改Maven軟件源為阿里云源的方法詳解

    這篇文章主要介紹了更改Maven軟件源為阿里云源的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Java中實現(xiàn) SHA-256加密的兩種方式

    Java中實現(xiàn) SHA-256加密的兩種方式

    這篇文章主要介紹了Java中實現(xiàn) SHA-256加密的兩種方式,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • IntelliJ IDEA中查看當前類的所有繼承關系圖

    IntelliJ IDEA中查看當前類的所有繼承關系圖

    今天小編就為大家分享一篇關于IntelliJ IDEA中查看當前類的所有繼承關系圖,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • Spring?Boot?整合RocketMq實現(xiàn)消息過濾功能

    Spring?Boot?整合RocketMq實現(xiàn)消息過濾功能

    這篇文章主要介紹了Spring?Boot?整合RocketMq實現(xiàn)消息過濾,本文講解了RocketMQ實現(xiàn)消息過濾,針對不同的業(yè)務場景選擇合適的方案即可,需要的朋友可以參考下
    2022-06-06
  • 五種Java多線程同步的方法

    五種Java多線程同步的方法

    這篇文章主要為大家詳細介紹了五種Java多線程同步的方法,需要的朋友可以參考下
    2015-09-09
  • JAVA8獲取list集合中重復的元素與獲取去重數(shù)據(jù)實例

    JAVA8獲取list集合中重復的元素與獲取去重數(shù)據(jù)實例

    這篇文章主要給大家介紹了關于JAVA8獲取list集合中重復的元素與獲取去重數(shù)據(jù)的相關資料,在實際開發(fā)中經(jīng)常會遇到需要找出(刪除)一個list中某些元素的屬性相同的元素,需要的朋友可以參考下
    2023-07-07
  • 一文弄懂Maven依賴范圍

    一文弄懂Maven依賴范圍

    本文詳細介紹了Maven依賴范圍的概念、應用及其在項目構建和管理中的重要性,依賴范圍包括compile、provided、runtime、test和system等類型,每種范圍定義了依賴在不同構建階段的可用性和打包行為,感興趣的可以了解一下
    2024-11-11
  • SpringBoot集成Shiro進行權限控制和管理的示例

    SpringBoot集成Shiro進行權限控制和管理的示例

    這篇文章主要介紹了SpringBoot集成Shiro進行權限控制和管理的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03

最新評論