一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - Android 單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析

Android 單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析

2020-07-15 12:24java教程網(wǎng) JAVA教程

這篇文章主要介紹了單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析的相關(guān)資料,需要的朋友可以參考下

單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析

前言

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

關(guān)于設(shè)計(jì)模式的介紹,可以看下我之前寫的:1分鐘全面了解“設(shè)計(jì)模式”

目錄

Android 單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析

1. 引入

1.1 解決的是什么問題

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

含義:?jiǎn)卫?=一個(gè)實(shí)例;

解決的問題:降低對(duì)象之間的耦合度

解決方法:?jiǎn)卫J剑磳?shí)現(xiàn)一個(gè)類只有一個(gè)實(shí)例化對(duì)象,并提供一個(gè)全局訪問點(diǎn)

1.2 實(shí)例引入

接下來我用一個(gè)實(shí)例來對(duì)單例模式進(jìn)行引入

背景:小成有一個(gè)塑料生產(chǎn)廠,但里面只有一個(gè)倉(cāng)庫(kù)。

目的:想用代碼來實(shí)現(xiàn)倉(cāng)庫(kù)的管理

現(xiàn)有做法: 建立倉(cāng)庫(kù)類和工人類

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package scut.designmodel.SingletonPattern;
 
 
//倉(cāng)庫(kù)類
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;
  }
  //搬貨進(jìn)倉(cāng)庫(kù)
  public void MoveIn(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
  }
  //搬貨出倉(cāng)庫(kù)
  public void MoveOut(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
  }
}
 
//工人搬運(yùn)測(cè)試
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("兩個(gè)是不是同一個(gè)?");
 
    if(mStoreHouse1.equals(mStoreHouse2)){//這里用equals而不是用 == 符號(hào),因?yàn)?== 符號(hào)只是比較兩個(gè)對(duì)象的地址
      System.out.println("是同一個(gè)");
    }else {
      System.out.println("不是同一個(gè)");
    }
    //搬運(yùn)工搬完貨物之后出來匯報(bào)倉(cāng)庫(kù)商品數(shù)量
    Carrier1.MoveIn(30);
    System.out.println("倉(cāng)庫(kù)商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉(cāng)庫(kù)商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

結(jié)果:

?
1
2
3
4
兩個(gè)是不是同一個(gè)?
不是同一個(gè)
倉(cāng)庫(kù)商品余量:130
倉(cāng)庫(kù)商品余量:50

2. 單例模式介紹

2.1 解決的問題(應(yīng)用場(chǎng)景)

沖突:從上面的結(jié)果可以看出,工人類操作的明顯不是同一個(gè)倉(cāng)庫(kù)實(shí)例。

目標(biāo):全部工人操作的是同一個(gè)倉(cāng)庫(kù)實(shí)例

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

在Java中,我們通過使用對(duì)象(類實(shí)例化后)來操作這些類,類實(shí)例化是通過它的構(gòu)造方法進(jìn)行的,要是想實(shí)現(xiàn)一個(gè)類只有一個(gè)實(shí)例化對(duì)象,就要對(duì)類的構(gòu)造方法下功夫:


Android 單例模式 Singleton 簡(jiǎn)單實(shí)例設(shè)計(jì)模式解析

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
//1. 創(chuàng)建私有變量 ourInstance(用以記錄 Singleton 的唯一實(shí)例)
//2. 內(nèi)部進(jìn)行實(shí)例化
  private static Singleton ourInstance = new Singleton();
 
//3. 把類的構(gòu)造方法私有化,不讓外部調(diào)用構(gòu)造方法實(shí)例化
  private Singleton() {
  }
//4. 定義公有方法提供該類的全局唯一訪問點(diǎn)
//5. 外部通過調(diào)用getInstance()方法來返回唯一的實(shí)例
  public static Singleton newInstance() {
    return ourInstance;
  }
}

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

2.3 實(shí)例介紹

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package scut.designmodel.SingletonPattern;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
//單例倉(cāng)庫(kù)類
class StoreHouse {
 
  //倉(cāng)庫(kù)商品數(shù)量
  private int quantity = 100;
  //自己在內(nèi)部實(shí)例化
  private static StoreHouse ourInstance = new StoreHouse();;
  //讓外部通過調(diào)用getInstance()方法來返回唯一的實(shí)例。
  public static StoreHouse getInstance() {
    return ourInstance;
  }
 
  //封閉構(gòu)造函數(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;
  }
  //搬貨進(jìn)倉(cāng)庫(kù)
  public void MoveIn(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
  }
  //搬貨出倉(cāng)庫(kù)
  public void MoveOut(int i){
    mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
  }
}
 
//工人搬運(yùn)測(cè)試
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("兩個(gè)是不是同一個(gè)?");
 
    if(mStoreHouse1.equals(mStoreHouse2)){
      System.out.println("是同一個(gè)");
    }else {
      System.out.println("不是同一個(gè)");
    }
    //搬運(yùn)工搬完貨物之后出來匯報(bào)倉(cāng)庫(kù)商品數(shù)量
    Carrier1.MoveIn(30);
    System.out.println("倉(cāng)庫(kù)商品余量:"+Carrier1.mStoreHouse.getQuantity());
    Carrier2.MoveOut(50);
    System.out.println("倉(cāng)庫(kù)商品余量:"+Carrier2.mStoreHouse.getQuantity());
  }
}

結(jié)果:

?
1
2
3
4
兩個(gè)是不是同一個(gè)?
是同一個(gè)
倉(cāng)庫(kù)商品余量:130
倉(cāng)庫(kù)商品余量:80

從結(jié)果分析,使用了單例模式后,倉(cāng)庫(kù)類就只有一個(gè)倉(cāng)庫(kù)實(shí)例了,再也不用擔(dān)心搬運(yùn)工人進(jìn)錯(cuò)倉(cāng)庫(kù)了!!!

2.4 優(yōu)點(diǎn)

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

2.5 缺點(diǎn)

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

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

3.1 一般情況

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

?
1
2
3
4
5
6
7
8
9
10
class Singleton {
  private static Singleton ourInstance = new Singleton();
 
  private Singleton() {
  }
 
  public static Singleton newInstance() {
    return ourInstance;
  }
}

應(yīng)用場(chǎng)景:

  • 要求直接在應(yīng)用啟動(dòng)時(shí)加載并初始化
  • 單例對(duì)象要求初始化速度非常快且占用內(nèi)存非常小

懶漢式

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

  • 餓漢式:自動(dòng)進(jìn)行單例的初始化
  • 懶漢式:有需要的時(shí)候才手動(dòng)調(diào)用newInstance()進(jìn)行單例的初始化操作
?
1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
  private static Singleton ourInstance = null
 
  private Singleton() {
  }
 
  public static Singleton newInstance() {
  if( ourInstance == null){
    ourInstance = new Singleton();
    }
    return ourInstance;
  }
}

應(yīng)用場(chǎng)景:

  • 單例初始化的操作耗時(shí)比較長(zhǎng)而應(yīng)用對(duì)于啟動(dòng)速度又有要求
  • 單例的占用內(nèi)存比較大
  • 單例只是在某個(gè)特定場(chǎng)景的情況下才會(huì)被使用,即按需延遲加載單例。

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

在多線程的情況下:

  • 對(duì)于“餓漢式單例模式”:適用,因?yàn)镴VM只會(huì)加載一次單例類;
  • 對(duì)于“懶漢式單例模式”:不適用,因?yàn)?ldquo;懶漢式”在創(chuàng)建單例時(shí)是線程不安全的,多個(gè)線程可能會(huì)并發(fā)調(diào)用 newInstance 方法從而出現(xiàn)重復(fù)創(chuàng)建單例對(duì)象的問題。

解決方案1:同步鎖

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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:雙重校驗(yàn)鎖

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)內(nèi)部類

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
 
  //在裝載該內(nèi)部類時(shí)才會(huì)去創(chuàng)建單例對(duì)象
  private static class Singleton2{
   private static Singleton ourInstance = new Singleton();
  }
  private Singleton() {
  }
 
  public static Singleton newInstance() {
    return Singleton2.ourInstance;
  }
}

解決方案4:枚舉類型

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

?
1
2
3
4
5
6
7
8
9
public enum Singleton{
 
  //定義一個(gè)枚舉的元素,它就是Singleton的一個(gè)實(shí)例
  instance;
 
  public void doSomething(){
  
 
}

使用方式如下:

?
1
2
Singleton singleton = Singleton.instance;
singleton.doSomething();

5. 總結(jié)

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

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

原文鏈接:http://blog.csdn.net/carson_ho/article/details/52223097

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 青青网在线视频 | 国产精品高清一区二区三区 | 四虎免费在线视频 | 四虎综合九九色九九综合色 | 极品妖艳许清赵丽全文免费阅读 | 日本一卡2卡3卡4卡乱 | 99这里只有精品视频 | 麻豆夏晴子 | 美女的隐私视频免费看软件 | 欧美一二区视频 | 大学生按摩黄a级中文片 | 动漫美女被吸乳羞羞小说 | 91麻豆影视 | 久久成人免费大片 | 日韩欧美一区二区三区中文精品 | 国产亚洲人成网站在线观看不卡 | 亚州男人天堂 | 俄罗斯激情性孕妇孕交大全 | 国产亚洲精品视频中文字幕 | 亚洲精品国产乱码AV在线观看 | 天天干天天爽天天操 | 四虎精品成人免费视频 | 91久久线看在观草草青青 | 韩国成人毛片aaa黄 含羞草国产亚洲精品岁国产精品 | 男男双性生子产乳高辣h | 欧美三级免费观看 | 秋霞一级成人欧美理论 | 天天干夜夜拍 | 精品在线看 | 亚洲成av人影院 | 久久99精国产一区二区三区四区 | 亚洲国产三级在线观看 | 风间由美被义子中文字幕 | 51国产午夜精品免费视频 | 热门小说同人h改编h | 高h全肉动漫在线观看免费 高h辣h双处全是肉军婚 | 欧美视频一区二区专区 | 欧美无专区 | 国产一卡二卡3卡4卡四卡在线视频 | 深夜在线观看网站 | 日本亚洲欧洲高清有码在线播放 |