程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Android 單例形式 Singleton 復雜實例設計形式解析

Android 單例形式 Singleton 復雜實例設計形式解析

編輯:關於JAVA

Android 單例形式 Singleton 復雜實例設計形式解析。本站提示廣大學習愛好者:(Android 單例形式 Singleton 復雜實例設計形式解析)文章只能為提供參考,不一定能成為您想要的結果。以下是Android 單例形式 Singleton 復雜實例設計形式解析正文


單例形式 Singleton 復雜實例設計形式解析

前言

明天我來片面總結一下Android開發中最常用的設計形式 - 單例形式。

關於設計形式的引見,可以看下我之前寫的:1分鐘片面理解“設計形式”

目錄

1. 引入

1.1 處理的是什麼問題

之前說過,設計形式 = 某類特定問題的處理方案,那麼單例形式是處理什麼問題的處理方案呢?

含義:單例 =一個實例;

處理的問題:降低對象之間的耦合度

處理辦法:單例形式,即完成一個類只要一個實例化對象,並提供一個全局訪問點

1.2 實例引入

接上去我用一個實例來對單例形式停止引入

背景:小成有一個塑料消費廠,但外面只要一個倉庫。

目的:想用代碼來完成倉庫的管理

現有做法: 樹立倉庫類和工人類

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

呈現的問題:經過測試發現,每次工人搬運操作都會新建一個倉庫,就是貨物都不是放在同一倉庫,這是怎樣回事呢?(看上面代碼)

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("不是同一個");
    }
    //搬運工搬完貨物之後出來匯報倉庫商品數量
    Carrier1.MoveIn(30);
    System.out.println("倉庫商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉庫商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

後果:

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

2. 單例形式引見

2.1 處理的問題(使用場景)

抵觸:從下面的後果可以看出,工人類操作的分明不是同一個倉庫實例。

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

單例形式就是為理解決這類問題的處理方案:完成一個類只要一個實例化對象,並提供一個全局訪問點2.2 任務原理

在Java中,我們經過運用對象(類實例化後)來操作這些類,類實例化是經過它的結構辦法停止的,要是想完成一個類只要一個實例化對象,就要對類的結構辦法下功夫:

單例形式的普通完成:(含運用步驟)

public class Singleton {
//1. 創立公有變量 ourInstance(用以記載 Singleton 的獨一實例)
//2. 外部停止實例化
  private static Singleton ourInstance = new Singleton();

//3. 把類的結構辦法公有化,不讓內部調用結構辦法實例化
  private Singleton() {
  }
//4. 定義私有辦法提供該類的全局獨一訪問點
//5. 內部經過調用getInstance()辦法來前往獨一的實例
  public static Singleton newInstance() {
    return ourInstance;
  }
}

好了,單例形式的引見和原理應該理解了吧?那麼我們如今來處理下面小成呈現的“倉庫不是一個”的問題吧!

2.3 實例引見

小成運用單例形式改善下面例子的代碼:

package scut.designmodel.SingletonPattern;

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

//單例倉庫類
class StoreHouse {

  //倉庫商品數量
  private int quantity = 100;
  //自己在外部實例化
  private static StoreHouse ourInstance = new StoreHouse();;
  //讓內部經過調用getInstance()辦法來前往獨一的實例。
  public static StoreHouse getInstance() {
    return ourInstance;
  }

  //封鎖結構函數
  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("不是同一個");
    }
    //搬運工搬完貨物之後出來匯報倉庫商品數量
    Carrier1.MoveIn(30);
    System.out.println("倉庫商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉庫商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

後果:

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

從後果剖析,運用了單例形式後,倉庫類就只要一個倉庫實例了,再也不必擔憂搬運工人進錯倉庫了!!!

2.4 優點

    提供了對獨一實例的受控訪問; 由於在零碎內存中只存在一個對象,因而可以浪費零碎資源,關於一些需求頻繁創立和銷毀的對象單例形式無疑可以進步零碎的功能; 可以依據實踐狀況需求,在單例形式的根底上擴展做出雙例形式,多例形式;

2.5 缺陷

    單例類的職責過重,外面的代碼能夠會過於復雜,在一定水平上違犯了“單一職責准繩”。 假如實例化的對象長時間不被應用,會被零碎以為是渣滓而被回收,這將招致對象形態的喪失。

3. 單例形式的完成方式

3.1 普通狀況

餓漢式(最復雜的單例完成方式)

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

  private Singleton() {
  }

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

使用場景:

要求直接在使用啟動時加載並初始化 單例對象要求初始化速度十分快且占用內存十分小

懶漢式

懶漢式與餓漢式最大的區別是單例的初始化操作的機遇:

餓漢式:自動停止單例的初始化 懶漢式:有需求的時分才手動調用newInstance()停止單例的初始化操作
class Singleton {
  private static Singleton ourInstance = null;

  private Singleton() {
  }

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

使用場景:

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

3.2 多線程下的單例形式完成

在多線程的狀況下:

關於“餓漢式單例形式”:適用,由於JVM只會加載一次單例類; 關於“懶漢式單例形式”:不適用,由於“懶漢式”在創立單例時是線程不平安的,多個線程能夠會並發調用 newInstance 辦法從而呈現反復創立單例對象的問題。

處理方案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曾經實例化後下次進入不用執行 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:靜態外部類

在JVM停止類加載的時分會保證數據是同步的,我們采用外部類完成:在外部類外面去創立對象實例。
只需使用中不運用外部類 JVM 就不會去加載這個單例類,也就不會創立單例對象,從而完成“懶漢式”的延遲加載和線程平安。

class Singleton {

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

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

處理方案4:枚舉類型

最簡約、易用的單例完成方式,(《Effective Java》引薦)

public enum Singleton{

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

  public void doSomething(){
  }  

}

運用方式如下:

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

5. 總結

本文次要對單例形式停止了片面引見,包括原理和完成方式,接上去我會持續解說其他設計形式,有興味可以持續關注

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved