亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

設(shè)計模式之單例模式

cnsworder / 1461人閱讀

摘要:反射攻擊首先我們來看一下反射調(diào)用,以雙重檢驗方式為例反射攻擊輸出結(jié)果是反射攻擊結(jié)果私有構(gòu)造方法被調(diào)用次私有構(gòu)造方法被調(diào)用次從結(jié)果可以看到,私有的構(gòu)造函數(shù)被調(diào)用了兩次,也就是說這樣的單例模式并不安全。

保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
——艾迪生維斯理 《設(shè)計模式》
版權(quán)聲明:本文為 冬夏 原創(chuàng)發(fā)表在公眾號「Android從入門到精通」,可以隨意轉(zhuǎn)載,但請注明出處。
概述

在我們?nèi)粘>帉懗绦虻臅r候,經(jīng)常需要一種這樣的對象。我們希望整個系統(tǒng)只有一個這樣的對象,不論在什么時候和不論在哪里獲取這個對象的時候,獲得的都是同一個對象。

比如說系統(tǒng)的任務(wù)管理器,我們希望整個系統(tǒng)只有一個任務(wù)管理器,不論什么時候打開任務(wù)管理器,都可以看到當(dāng)前系統(tǒng)的所有任務(wù),而不是把任務(wù)分散在很多個任務(wù)管理器里。

又比如說打印機,當(dāng)電腦連接上一臺打印機的時候,我們會希望不管是在文檔A里使用或者在文檔B里使用的時候,都是同一臺打印機,而且能夠按順序打印。

我們把這種類似的需求不斷總結(jié)并歸納起來,就成了單例模式。

單例模式可以說是所有設(shè)計模式里面最簡單的了,但是要靈活并且準(zhǔn)確地使用它也不是那么容易的。

首先觀察一下單例模式的 UML 圖。

從 UML 圖中我們可以觀察到單例模式的幾個特點

私有的、靜態(tài)的實例對象

私有的構(gòu)造函數(shù)

公有的、靜態(tài)的獲取實例對象的方法

那么,什么樣的代碼可以同時滿足這幾個特點呢?

懶漢模式

所謂的懶漢模式,就是一開始并不實例化對象,等到需要使用的時候才實例化。

{% codeblock 懶漢模式 lang:java %}
public class Singleton {

  private static Singleton instance = null;

  private Singleton(){}

  public static Singleton getInstance() {
      if (instance == null)
      {
          instance = new Singleton();
      }
      return instance;
  }
}
{% endcodeblock %}

從上面的代碼我們可以看到,當(dāng)?shù)谝淮潍@取 Singleton 實例的時候,instance 為空,將創(chuàng)建 Singleton 對象,并賦值給 instance 變量。以后的每次一獲取都將獲得第一次創(chuàng)建的 Singleton 對象,從而實現(xiàn)了唯一性。

線程安全驗證

仔細(xì)想想這段代碼,可能存在什么問題呢?

假設(shè)有這么一種情況, Singleton 對象還沒有創(chuàng)建,這時候有很多個線程同時獲取 Singleton 對象,這時候會發(fā)生什么呢?

用下面的代碼可以驗證

{% codeblock 懶漢模式 線程安全驗證 lang:java %}
public class Singleton {
  private static int count = 0;

  private static Singleton instance = null;

  private Singleton(){
      try {
          Thread.sleep(10);
      }catch (InterruptedException e){

      }
      System.out.println("Singleton 私有構(gòu)造方法被調(diào)用 " + ++count + "次");
  }

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


public class Test {
  public static void main(String[] args){

      Runnable runnable = new Runnable() {
          @Override
          public void run() {
              Singleton singleton = Singleton.getInstance();
              System.out.println("當(dāng)前線程:" + Thread.currentThread().getName() +
                      " Singleton: " + singleton.hashCode());
          }
      };

      for (int i = 0; i < 10; i++){
          new Thread(runnable).start();
      }
  }
}
{% endcodeblock %}

從上面的代碼可以看到,我們對懶漢模式做了一點小修正,在創(chuàng)建 Singleton 對象的時候讓當(dāng)前線程休眠了10ms,這主要是因為計算機運算速度太快了,不讓當(dāng)前線程休眠一下的話很難出現(xiàn)想要的結(jié)果。關(guān)于休眠我們可以把它想象成創(chuàng)建對象的過程中需要消耗一定的時間。

運算部分結(jié)果如下:

{% codeblock 懶漢模式 線程安全驗證結(jié)果 lang:java %}
Singleton 私有構(gòu)造方法被調(diào)用 1次
當(dāng)前線程:Thread-1 Singleton: 2044439889
Singleton 私有構(gòu)造方法被調(diào)用 4次
Singleton 私有構(gòu)造方法被調(diào)用 3次
Singleton 私有構(gòu)造方法被調(diào)用 2次
當(dāng)前線程:Thread-0 Singleton: 605315508
當(dāng)前線程:Thread-2 Singleton: 2298428
當(dāng)前線程:Thread-3 Singleton: 1005746524
當(dāng)前線程:Thread-4 Singleton: 1005746524
當(dāng)前線程:Thread-5 Singleton: 1005746524
當(dāng)前線程:Thread-6 Singleton: 1005746524
當(dāng)前線程:Thread-7 Singleton: 1005746524
當(dāng)前線程:Thread-8 Singleton: 1005746524
當(dāng)前線程:Thread-9 Singleton: 1005746524
{% endcodeblock %}

從上面的結(jié)果可以看到,Singleton 的私有構(gòu)造方法被調(diào)用了不止一次。對此的解釋是,當(dāng)?shù)谝淮潍@取 Singleton 對象還沒完成的時候,線程被系統(tǒng)掛起了,這時候有其他線程剛好也獲取了 Singleton 對象,那么就會產(chǎn)生多個 Singleton 對象。

由此我們可以得出結(jié)論:懶漢模式是 非線程安全 的。

同步方法

為了解決懶漢模式非線程安全的缺點,就出現(xiàn)了改進的懶漢模式。其原理是當(dāng)多個線程同時獲取 Singleton 對象時,一次只讓一個線程獲取,其他線程都在等待,這樣就解決了多線程下的對象獲取問題。

{% codeblock 同步方法 lang:java %}
public class Singleton {
  private static Singleton instance = null;

  private Singleton(){}

  public static synchronized Singleton getInstance() {
      if (instance == null)
      {
          instance = new Singleton();
      }
      return instance;
  }
}
{% endcodeblock %}

我們通過 synchronized 關(guān)鍵字讓 getInstance()方法一次只能讓一個線程調(diào)用,但是隨著而來的又有另外一個問題。

那就是 效率問題,因為只有第一次獲取 Singleton 對象時有可能發(fā)生線程安全問題,但是使用同步方法卻讓每次只讓一個線程能訪問getInstance()方法,而不管 Singleton 對象是不是已經(jīng)被創(chuàng)建出來了。

那么有沒有辦法能同時解決線程安全和效率問題呢?

雙重校驗

雙重校驗 方式就是為了解決懶漢模式的線程安全和效率問題而產(chǎn)生的。

{% codeblock 雙重校驗 lang:java %}
public class Singleton {

  private static Singleton instance = null;

  private Singleton(){}

  public static Singleton getInstance() {
      if (instance == null){
          synchronized (Singleton.class){
              if (instance == null){
                  instance = new Singleton();
              }
          }
      }
      return instance;
  }
}
{% endcodeblock %}

雙重校驗就是將前面兩種懶漢模式結(jié)合起來。當(dāng)?shù)谝淮潍@取 Singleton 對象時, instance 為空, 這時候為了解決可能存在的線程安全問題,同步了 Singleton 這個類對象。也就是說,同一時刻只能有一個線程能夠執(zhí)行 synchronized 之后的代碼。同時因為同步代碼外層有一個條件語句,所以同步代碼只有在第一次獲取 Singleton 對象的時候執(zhí)行到,這樣就解決了效率問題。

但是這種方法還是有一個問題,那就是 instance = new Singleton() 這一行代碼并不是原子性的

具體來說,JVM執(zhí)行這一行代碼時主要做了三件事

給 instance 分配內(nèi)存空間

調(diào)用 Singleton 的構(gòu)造函數(shù)來初始化成員變量

將 instance 變量指向分配的內(nèi)存空間(執(zhí)行完這一步之后 instance 就不為 null 了)

由于 JVM 的指令優(yōu)化存在,上面的第二點和第三點并不能保證一定按順序執(zhí)行。也就是說執(zhí)行順序有可能為 1-2-3 或者 1-3-2。

假設(shè)是 1-3-2,那么如果執(zhí)行到3的時候,線程被搶占了,有另外一個線程獲取了單例對象(這時候 instance 不為 null,但是還沒有初始化),那么自然就會出現(xiàn)錯誤。

為了解決這個問題,我們只要將 instance 變量聲明成 volatile 就可以了。

private static volatile Singleton instance = null;

volatile 關(guān)鍵字主要有兩個特性

可見性:保證線程沒有變量的本地副本,每次都去主內(nèi)存獲取最新版本

禁止指令重排序:生成內(nèi)存屏障

很明顯,我們這里利用的是 volatile 的第二個特性。

特別注意的是只有在 Java 5 之后使用這種方式才是完全安全的,原因是 Java 5 之前的 Java 內(nèi)存模型(Java Memory Model,JMM)存在缺陷,即使變量聲明為 volatile 也不能完全避免重排序,這個問題在 Java 5 之后才修復(fù)。

惡漢模式

這時候我們可以換個思路,既然懶漢模式是因為需要的時候才創(chuàng)建對象,所以才讓程序有機會可以產(chǎn)生多個對象。那如果我一開始就把對象創(chuàng)建好了,不就行了嗎?這就出現(xiàn)了惡漢模式。

惡漢模式的意思是不管對象目前有沒有使用,都會先創(chuàng)建出來。

{% codeblock 惡漢模式 lang:java %}
public class Singleton {

  private static final Singleton instance = new Singleton();

  private Singleton(){}

  public static Singleton getInstance() {
      return instance;
  }
}
{% endcodeblock %}

從代碼中可以看到,由于在 Singleton 類加載時就創(chuàng)建了 Singleton 對象,所以惡漢模式是 線程安全 的。

但是惡漢模式存在的問題就是不管目前對象有沒有被使用,都被創(chuàng)建了出來,浪費了內(nèi)存空間。

靜態(tài)方法

靜態(tài)方法的單例模式和惡漢模式的原理一樣,都是利用了classloader,在類加載的時候就創(chuàng)建了 Singleton 對象。

{% codeblock 靜態(tài)方法 lang:java %}
public class Singleton {

  private static Singleton instance = null;

  static {
      instance = new Singleton();
  }
  private Singleton(){}

  public static Singleton getInstance() {
      return instance;
  }
}
{% endcodeblock %}
靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類的方法和上面兩種方法既有相似的地方,也有不同的地方。

{% codeblock 靜態(tài)內(nèi)部類 lang:java %}
public class Singleton {

  private static class SingletonHolder{
      private static final Singleton INSTANCE = new Singleton();
  }
  private Singleton(){}

  public static Singleton getInstance() {
      return SingletonHolder.INSTANCE;
  }
}
{% endcodeblock %}

從代碼種我們可以看到,靜態(tài)內(nèi)部類的方法和前兩種方法一樣,都是利用了classloader,在加載類的時候創(chuàng)建 Singleton 對象。

不同的地方在于加載的類不同。靜態(tài)內(nèi)部類方法在加載 Singleton 類的時候不會創(chuàng)建 Singleton 對象。而是在加載 SingletonHolder 類的時候才會。那么 SingletonHolder 類是什么時候加載的呢?

根據(jù)JVM(Java 虛擬機)的類加載規(guī)則,靜態(tài)內(nèi)部類只有在主動調(diào)用的時候才會加載。也就是說,在第一次調(diào)用 getInstance() 方法時才會加載 SingletonHolder 類,同時創(chuàng)建了 Singleton 對象。

也可以說,靜態(tài)內(nèi)部類的方法利用JVM解決了前兩種方法占用內(nèi)存的問題。

防止單例受到攻擊

到目前為止,我們所分析的所有單例模式都有一個前提,那就是調(diào)用者非常聽話地使用了 Singleton.getInstance() 方法獲取單例對象。但是在現(xiàn)實生活中是不是都是這樣的呢?會不會有不懷好意的人使用其他方式破壞我們的單例模式呢?

我們先思考一下,獲取一個對象有幾種方式

使用 new 關(guān)鍵字

通過反射調(diào)用

序列化

我們前面的單例模式都是通過第一種方式獲取對象的,那么如果采用其他兩種方式,之前的單例模式還安全嗎?答案是否定的。

反射攻擊

首先我們來看一下反射調(diào)用,以雙重檢驗方式為例

{% codeblock 反射攻擊 lang:java %}
public class Singleton {

  private static volatile Singleton instance = null;

  private Singleton(){}

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

public class Test {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException{

        Singleton singleton1 = Singleton.getInstance();

        Class classType = Singleton.class;
        Constructor constructor = classType.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        Singleton singleton2 = (Singleton) constructor.newInstance();
        System.out.println(singleton1 == singleton2);  //false
    }
}
{% endcodeblock %}

輸出結(jié)果是

{% codeblock 反射攻擊結(jié)果 lang:java %}
Singleton 私有構(gòu)造方法被調(diào)用 1次
Singleton 私有構(gòu)造方法被調(diào)用 2次
false
{% endcodeblock %}

從結(jié)果可以看到,私有的構(gòu)造函數(shù)被調(diào)用了兩次,也就是說這樣的單例模式并不安全。

為了防止單例模式被反射攻擊,我們可以添加一個標(biāo)志位,在新建對象時判斷是否已經(jīng)新建過對象了。

{% codeblock 防止反射攻擊 lang:java %}
public class Singleton {

  private static boolean flag = false;

  private static volatile Singleton instance = null;

  private Singleton(){

      if (!flag){
          flag = true;
      }else {
          throw new RuntimeException("構(gòu)造函數(shù)被調(diào)用多次");
      }
  }

  public static Singleton getInstance() {
      if (instance == null){
          synchronized (Singleton.class){
              if (instance == null){
                  instance = new Singleton();
              }
          }
      }
      return instance;
  }
}
{% endcodeblock %}

當(dāng)然這種方式也有一個缺點,那就是必須保證 Singleton.getInstance() 方法在反射之前調(diào)用,否則將不能正確獲取單例對象。

而且,既然我們可以通過反射創(chuàng)建出對象,那么也可以通過反射修改標(biāo)志位的值,這樣一來,使用標(biāo)志位的方法就不能完全防止反射攻擊了。

序列化攻擊

接下來我們看一下序列化如何破壞單例模式,以惡漢模式為例。

{% codeblock 序列化攻擊 lang:java %}
public class Singleton implements Serializable{

  private static final Singleton instance = new Singleton();

  private Singleton(){}

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

public class Test {
  public static void main(String[] args) throws IOException,ClassNotFoundException{

      Singleton singleton1 = Singleton.getInstance();
      Singleton singleton2;

      FileOutputStream fos = new FileOutputStream("SerSingleton.obj");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(singleton1);
      oos.flush();
      oos.close();

      FileInputStream fis = new FileInputStream("SerSingleton.obj");
      ObjectInputStream ois = new ObjectInputStream(fis);
      singleton2 = (Singleton)ois.readObject();

      System.out.println(singleton1==singleton2);
  }
}
{% endcodeblock %}

輸出結(jié)果為 false 表明我們的單例收到了攻擊,那么如何防止這種情況呢?

我們可以在被序列化的類中添加readResolve方法

{% codeblock 防止序列化攻擊 lang:java %}
public class Singleton implements Serializable{

  private static final Singleton instance = new Singleton();

  private Singleton(){}

  public static Singleton getInstance() {
      return instance;
  }

  private Object readResolve(){
      return instance;
  }
}
{% endcodeblock %}

說了這么多,不知道大家有沒有這樣一種感慨 「 都說單例模式是最簡單的一種模式,這么還這么復(fù)雜,以后還讓不讓人活了 」。

那么有沒有一種又簡單有能防止所有攻擊的方法呢?

枚舉

枚舉( enum )是 Java1.5 之后新加的特性。

大家一定很奇怪,為什么枚舉可以實現(xiàn)單例呢?其實和 Java 的編譯特性有關(guān)。因為枚舉是 Java1.5 之后新加的,一般新加入的功能有一個很重要的問題需要解決,就是對以前代碼的兼容性問題。而 Java 是通過 語法糖 的方式解決的。簡單來說就是編寫代碼的時候可以使用新的關(guān)鍵字 enum 編寫程序,但是 Java 編譯器在編譯成字節(jié)碼的時候,還是會利用現(xiàn)有的技術(shù)編譯成之前的 JVM 能夠識別并正確運行的字節(jié)碼,這就是語法糖技術(shù)。

我們先來看一下枚舉編寫的單例是什么樣子的。

{% codeblock 枚舉 lang:java %}
public enum Singleton {

  INSTANCE;

  public static Singleton getInstance(){
      return INSTANCE;
  }

  public void otherMethods(){
      System.out.println("do something");
  }
}
{% endcodeblock %}

這段代碼看起來很簡單,我們定義了一個枚舉類型 INSTANCE, 這就是我們需要的單例。但是為什么這樣就能實現(xiàn)線程安全的單例呢?要解決這個疑問,我們必須把這段代碼進行反編譯,看看 java 編譯器究竟是如何編譯這段代碼的。

我們使用 java 自帶的反編譯工具 javap 就可以將這段代碼反編譯

javap -c Singleton

反編譯結(jié)果如下:

{% codeblock 反編譯 lang:java %}
public final class Singleton extends java.lang.Enum {
public static final Singleton INSTANCE;

public static Singleton[] values();
  Code:
     0: getstatic     #1                  // Field $VALUES:[LSingleton;
     3: invokevirtual #2                  // Method "[LSingleton;".clone:()Ljava/lang/Object;
     6: checkcast     #3                  // class "[LSingleton;"
     9: areturn

public static Singleton valueOf(java.lang.String);
  Code:
     0: ldc           #4                  // class Singleton
     2: aload_0
     3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
     6: checkcast     #4                  // class Singleton
     9: areturn

public static Singleton getInstance();
  Code:
     0: getstatic     #7                  // Field INSTANCE:LSingleton;
     3: areturn

public void otherMethods();
  Code:
     0: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #9                  // String do something
     5: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     8: return

static {};
  Code:
     0: new           #4                  // class Singleton
     3: dup
     4: ldc           #11                 // String INSTANCE
     6: iconst_0
     7: invokespecial #12                 // Method "":(Ljava/lang/String;I)V
    10: putstatic     #7                  // Field INSTANCE:LSingleton;
    13: iconst_1
    14: anewarray     #4                  // class Singleton
    17: dup
    18: iconst_0
    19: getstatic     #7                  // Field INSTANCE:LSingleton;
    22: aastore
    23: putstatic     #1                  // Field $VALUES:[LSingleton;
    26: return
}
{% endcodeblock %}

可能這段代碼對于剛剛接觸 java 的人來說一時可能看不懂,但是我們只要關(guān)注到一下幾點就好了。

public final class Singleton extends java.lang.Enum 這說明枚舉類型實際上被 java 編譯器通過語法糖轉(zhuǎn)換成了不可變類,繼承自 Enum 類。

public static final Singleton INSTANCE,說明我們定義的枚舉值 INSTANCE 實際上被 java 編譯器轉(zhuǎn)換成了不可變對象,只可以初始化一次。

關(guān)注到 INSTANCE 實際上是在 static {} 這段代碼里初始化的。也就是說, INSTANCE 是在 Singleton 類加載的時候初始化的,所以一旦 Singleton 類加載了,INSTANCE 也就初始化了,不能再改變了,這就實現(xiàn)了單例模式。

然后如果我們嘗試使用序列化或者反射的方式去攻擊枚舉單例,會發(fā)現(xiàn)都不能成功,這是由于 JVM 實現(xiàn)枚舉的機制決定的。

最后,引用一下 《Effective Java》一書中的話。

單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法。
——《Effective Java》

歡迎關(guān)注我的個人公眾號,一起學(xué)習(xí)Android、Java、設(shè)計模式等技術(shù)!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/68109.html

相關(guān)文章

  • 大話PHP設(shè)計模式單例模式升級版

    摘要:用來指向已創(chuàng)建好的實例構(gòu)造函數(shù)為空注意這里是關(guān)鍵這是我們需要調(diào)用的方法把函數(shù)也定義為空,這樣就大功告成啦。 接上一篇大話PHP設(shè)計模式之單例模式 這一篇介紹一下升級版的單例模式,廢話不說先上代碼 不完美的單例模式 class singleMode { //用來指向已創(chuàng)建好的實例 public static $instance; //判斷是...

    darcrand 評論0 收藏0
  • 每天一個設(shè)計模式單例模式

    摘要:博主按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語言實現(xiàn)。單例模式用途如果一個類負(fù)責(zé)連接數(shù)據(jù)庫的線程池日志記錄邏輯等等,此時需要單例模式來保證對象不被重復(fù)創(chuàng)建,以達到降低開銷的目的。 博主按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實...

    yy736044583 評論0 收藏0
  • 每天一個設(shè)計模式單例模式

    摘要:博主按每天一個設(shè)計模式旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語言實現(xiàn)。單例模式用途如果一個類負(fù)責(zé)連接數(shù)據(jù)庫的線程池日志記錄邏輯等等,此時需要單例模式來保證對象不被重復(fù)創(chuàng)建,以達到降低開銷的目的。 博主按:《每天一個設(shè)計模式》旨在初步領(lǐng)會設(shè)計模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語言實現(xiàn)。誠然,每種設(shè)計模式都有多種實...

    lijy91 評論0 收藏0
  • 大話PHP設(shè)計模式單例模式

    摘要:上面是簡單的單例模式,自己寫程序的話夠用了,如果想繼續(xù)延伸,請傳送至大話設(shè)計模式之單例模式升級版 看了那么多單例的介紹,都是上來就說怎么做,也沒見說為什么這么做的。那小的就來說說為什么會有單例這個模式以便更好的幫助初學(xué)者真正的理解這個設(shè)計模式,如果你是大神,也不妨看完指正一下O(∩_∩)O首先我不得不吐槽一下這個模式名字單例,初學(xué)者通過字面很難理解什么是單例,我覺得應(yīng)該叫唯一模式更貼切...

    VEIGHTZ 評論0 收藏0
  • 優(yōu)才公開課筆記:php設(shè)計模式(一) 單例模式

    摘要:最近開展了三次設(shè)計模式的公開課,現(xiàn)在來總結(jié)一下設(shè)計模式在中的應(yīng)用,這是第一篇創(chuàng)建型模式之單例模式。不過因為不支持多線程所以不需要考慮這個問題了。 最近開展了三次設(shè)計模式的公開課,現(xiàn)在來總結(jié)一下設(shè)計模式在PHP中的應(yīng)用,這是第一篇創(chuàng)建型模式之單例模式。 一、設(shè)計模式簡介 首先我們來認(rèn)識一下什么是設(shè)計模式: 設(shè)計模式是一套被反復(fù)使用、容易被他人理解的、可靠的代碼設(shè)計經(jīng)驗的總結(jié)。 設(shè)計模式不...

    guyan0319 評論0 收藏0
  • JavaScript設(shè)計模式單例模式

    摘要:原文博客地址單例模式系統(tǒng)中被唯一使用,一個類只有一個實例。中的單例模式利用閉包實現(xiàn)了私有變量兩者是否相等弱類型,沒有私有方法,使用者還是可以直接一個,也會有方法分割線不是單例最簡單的單例模式,就是對象。 原文博客地址:https://finget.github.io/2018/11/06/single/ 單例模式 系統(tǒng)中被唯一使用,一個類只有一個實例。實現(xiàn)方法一般是先判斷實例是否存在,...

    lk20150415 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<