程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 舉例講授C#編程中對設計形式中的單例形式的應用

舉例講授C#編程中對設計形式中的單例形式的應用

編輯:C#入門知識

舉例講授C#編程中對設計形式中的單例形式的應用。本站提示廣大學習愛好者:(舉例講授C#編程中對設計形式中的單例形式的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是舉例講授C#編程中對設計形式中的單例形式的應用正文


單例形式的引見
說到單例形式,年夜家第一反響應當就是——甚麼是單例形式?,從“單例”字面意思上懂得為——一個類只要一個實例,所以單例形式也就是包管一個類只要一個實例的一種完成辦法而已,上面給出單例形式的一個官方界說:確保一個類只要一個實例,並供給一個全局拜訪點。為了贊助年夜家更好地輿解單例形式,年夜家可以聯合上面的類圖來停止懂得,和前面也會分析單例形式的完成思緒:

https://www.aspphp.online/bianchen/UploadFiles_4619/201707/2017072810324930.png (813×515)

為何會有單例形式
看完單例形式的引見,天然年夜家都邑有如許一個疑問——為何要有單例形式的?它在甚麼情形下應用的?從單例形式的界說中我們可以看出——單例形式的應用天然是當我們的體系中某個對象只須要一個實例的情形,例如:操作體系中只能有一個義務治理器,操作文件時,統一時光內只許可一個實例對其操作等,既然實際生涯中有如許的運用場景,天然在軟件設計范疇必需有如許的處理計劃了(由於軟件設計也是實際生涯中的籠統),所以也就有了單例形式了。

分析單例形式的完成思緒
懂得完了一些關於單例形式的根本概念以後,上面就為年夜家分析單例形式的完成思緒的,由於在我本身進修單例形式的時刻,咋一看單例形式的完成代碼確切很簡略,也很輕易看懂,然則我照樣認為它很生疏(這個能夠是看的少的,或許本身在寫代碼中也用的少的原因),並且心裡總會如許一個疑問——為何後人會如許去完成單例形式的呢?他們是若何思慮的呢?前面經由本身的揣摩也就漸漸理清晰單例形式的完成思緒了,而且此時也不再認為單例形式形式的,上面就分享我的一個分析進程的:

我們從單例形式的概念(確保一個類只要一個實例,並供給一個拜訪它的全局拜訪點)動手,可以把概念停止拆分為兩部門:(1)確保一個類只要一個實例;(2)供給一個拜訪它的全局拜訪點;上面經由過程采取兩人對話的方法來贊助年夜家更快控制剖析思緒:

菜鳥:如何確保一個類只要一個實例了?

老鳥:那就讓我幫你剖析下,你創立類的實例會想到用甚麼方法來創立的呢?

老手:用new症結字啊,只需new下就創立了該類的一個實例了,以後便可以應用該類的一些屬性和實例辦法了

老鳥:那你想過為何可使用new症結字來創立類的實例嗎?

菜鳥:這個還有前提的嗎?........., 哦,我想起來了,假如類界說公有的結構函數就不克不及在外界經由過程new創立實例了(注:有些初學者就會問,有時刻我並沒有在類中界說結構函數為何也能夠應用new來創立對象,那是由於編譯器在面前做了四肢舉動了,當編譯器看到我們類中沒有界說結構函數,此時編譯器會幫我們生成一個私有的無參結構函數)

老鳥:不錯,答復的很對,如許你的困惑就獲得解答了啊

菜鳥:那我要在哪裡創立類的實例了?

老鳥:你傻啊,固然是在類外面創立了(注:如許界說公有結構函數就是下面的一個思慮進程的,要創立實例,天然就要有一個變量來保留該實例把,所以就有了公有變量的聲明,然則完成中是界說靜態公有變量,同伙們有無想過——這裡為何界說為靜態的呢?關於這個疑問的說明為:每一個線程都有本身的線程棧,界說為靜態重要是為了在多線程確保類有一個實例)

菜鳥:哦,如今完整明確了,然則我還有另外一個疑問——如今類實例創立在類外部,那外界若何取得該的一個實例來應用它了?

老鳥:這個,你可以界說一個私有辦法或許屬性來把該類的實例地下出去了(注:如許就有了私有辦法的界說了,該辦法就是供給辦法問類的全局拜訪點)

經由過程下面的剖析,信任年夜家也就很輕易寫出單例形式的完成代碼了,上面就看看詳細的完成代碼(看完以後你會驚奇道:真是如許的!):

上面是Singleton.cs的內容:

using System; 
using System.Collections; 
using System.Collections.Generic; 
  
  
public class Singleton : MonoBehaviour 
{ 
  private static GameObject m_Container = null; 
  private static string m_Name = "Singleton"; 
  private static Dictionary<string, object> m_SingletonMap = new Dictionary<string, object>(); 
  private static bool m_IsDestroying = false; 
    
  public static bool IsDestroying 
  { 
    get { return m_IsDestroying; } 
  } 
    
  public static bool IsCreatedInstance(string Name) 
  { 
    if(m_Container == null) 
    { 
      return false; 
    } 
    if (m_SingletonMap!=null && m_SingletonMap.ContainsKey(Name))  
    { 
      return true; 
    } 
    return false; 
      
  } 
  public static object getInstance (string Name) 
  { 
    if(m_Container == null) 
    { 
      Debug.Log("Create Singleton."); 
      m_Container = new GameObject (); 
      m_Container.name = m_Name;   
      m_Container.AddComponent (typeof(Singleton)); 
    } 
    if (!m_SingletonMap.ContainsKey(Name)) { 
      if(System.Type.GetType(Name) != null) 
      { 
        m_SingletonMap.Add(Name, m_Container.AddComponent (System.Type.GetType(Name))); 
      } 
      else 
      { 
        Debug.LogWarning("Singleton Type ERROR! (" + Name + ")"); 
      } 
    } 
    return m_SingletonMap[Name]; 
  }   
    
  public void RemoveInstance(string Name) 
  { 
    if (m_Container != null && m_SingletonMap.ContainsKey(Name)) 
    { 
      UnityEngine.Object.Destroy((UnityEngine.Object)(m_SingletonMap[Name])); 
      m_SingletonMap.Remove(Name); 
        
      Debug.LogWarning("Singleton REMOVE! (" + Name + ")"); 
    } 
  } 
  
  void Awake () 
  { 
    Debug.Log("Awake Singleton."); 
    DontDestroyOnLoad (gameObject); 
  } 
    
  void Start() 
  { 
    Debug.Log("Start Singleton."); 
  }   
    
  void Update() 
  { 
  } 
    
  void OnApplicationQuit() 
  { 
    Debug.Log("Destroy Singleton"); 
    if(m_Container != null) 
    { 
      GameObject.Destroy(m_Container); 
      m_Container = null; 
      m_IsDestroying = true; 
    }       
  } 
    
}

代碼年夜部門都比擬輕易看懂,上面引見幾點留意的處所:
當我們在其他代碼裡須要拜訪某個單例時,只需挪用getInstance函數便可,參數是須要拜訪的劇本的名字。我們來看一下這個函數。它起首斷定一切單例地點的容器m_Container能否為空(現實上就是場景中能否存在一個Gameobject,下面綁縛了一個Singleton劇本),假如為空,它將主動創立一個對象,然後以“Singleton”定名,再綁縛Singleton劇本。m_SingletonMap是擔任保護一切單例的映照。當第一次拜訪某個單例時,它會主動向m_Container上添加一個該單例類型的Component,並保留在單例映照中,再前往這個單例。是以,我們可以看出,單例的創立完整都是主動的,你完整不須要斟酌在哪裡、在甚麼時刻綁縛劇本,這是何等使人愉快得工作!
在Awake函數中,有一句代碼DontDestroyOnLoad (gameObject);,這長短常主要的,這句話意味著,當我們的場景產生變更時,單例形式將不受任何影響。除此以外,我們還要留意到,這句話也必需放到Awake函數,而不克不及放到Start函數中,這是由兩個函數的履行次序決議的,假如反過去,即可能會形成拜訪單例不勝利,上面的例子裡會更具體的引見;
在OnApplicationQuit函數中,我們將燒毀單例形式。
最初一點很主要:必定不要在OnDestroy函數中直接拜訪單例形式!如許很有能夠會形成單例沒法燒毀。這是由於,當法式加入預備燒毀單例形式時,我們在其他劇本的OnDestroy函數中再次要求拜訪它,如許將從新結構一個新的單例而不會被燒毀(由於之前曾經燒毀過一次了)。假如必定要拜訪的話,必定要先挪用IsCreatedInstance,斷定該單例能否存在。

.NET完成單例形式的類
懂得完了單例形式以後,菜鳥又接著問了:.NET FrameWork類庫中有無單例形式的完成呢?

經由檢查,.NET類庫中確切存在單例形式的完成類,不外該類不是地下的,上面就詳細看看該類的一個完成的(該類詳細存在於System.dll法式集,定名空間為System,年夜家可以用反射對象Reflector去檢查源碼的):

// 該類不是一個地下類
  // 然則該類的完成運用了單例形式
  internal sealed class SR
  {
    private static SR loader;
    internal SR()
    {
    }
    // 重要是由於該類不是私有,所以這個全體拜訪點也界說為公有的了
    // 然則思惟照樣用到了單例形式的思惟的
    private static SR GetLoader()
    {
      if (loader == null)
      {
        SR sr = new SR();
        Interlocked.CompareExchange<SR>(ref loader, sr, null);
      }
      return loader;
    }
    // 這個私有辦法中挪用了GetLoader辦法的
    public static object GetObject(string name)
    {
      SR loader = GetLoader();
      if (loader == null)
      {
        return null;
      }
      return loader.resources.GetObject(name, Culture);
    }
  }

總結
到這裡,設計形式的單例形式就引見完了,願望經由過程本文章年夜家可以對單例形式有一個更深的懂得,而且願望之前沒接觸過單例形式或認為單例形式生疏的同伙看完以後會贊歎:本來如斯!

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