2010-10-20 51 views
1

我想設計一個類,它將以類似於單例的方式存在,該類將有一個主實例,但也可能有多個克隆的主要實例。只有1個類可以創建主實例,其他人都可以創建一個克隆。像這樣的東西(c#):如何設計一個可以僅由1個類實例化的單例

class Singleton 
{ 
    private static Singleton _mainInstance; 
    private Singleton() {..} 
    public void Clone() {..} 

    public static Singleton MainInstance 
    { 
     if (_mainInstance == null) 
     { 
      _mainInstance = new Singleton();  // how to secure this for only 1 class? 
     } 
     return _mainInstance; 
    } 
} 


class MainClass 
{ 
    public MainClass() 
    { 
     Singleton.MainInstance .... 
    } 
} 

MainClass應該是唯一允許實例化單例的類。在C++中,可以通過完全隱藏創建邏輯並將MyClass作爲Singleton的朋友來完成。

+1

什麼是單身人士的克隆?同一對象(通過引用)或克隆時具有相同狀態的新對象?如果第一,你的問題是自我多餘的,如果第二,不要稱之爲單身...原型可能? – 2010-10-20 16:59:48

回答

2

下面是一個完整的工作實現,演示了兩種可能的方法來完成你想要的。

這兩種方法都使用工廠概念;由於Singleton的構造函數是私有的,因此只有嵌套的Factory類才能創建Singleton類的新實例。由於嵌套Factory類本身是私有的,獲得工廠實例的唯一方法是通過Singleton.GetFactoryFirstOneWins方法(「第一個獲勝」方法)或Singleton.AssignFactories方法(「間接分配」方法)。

interface IFactory<T> 
{ 
    T CreateInstance(); 
} 

class Singleton 
{ 
    class Factory : IFactory<Singleton> 
    { 
     public Singleton CreateInstance() 
     { 
      // return a clone of _MainInstance 
      return new Singleton(_MainInstance); 
     } 
    } 

    // *** Begin "First one wins" approach 
    static IFactory<Singleton> _FactoryFirstOneWins; 

    public static IFactory<Singleton> GetFactoryFirstOneWins() 
    { 
     if (_FactoryFirstOneWins != null) 
      throw new InvalidOperationException("A factory has already been created."); 

     return _FactoryFirstOneWins = new Factory(); 
    } 
    // *** End "First one wins" approach 

    // *** Begin "Indirect assignment" approach 
    public static void AssignFactories() 
    { 
     MainClass.SingletonFactory = new Factory(); 
    } 
    // *** End "Indirect assignment" approach 

    private static readonly Singleton _MainInstance = new Singleton(); 

    public static Singleton MainInstance 
    { 
     get { return _MainInstance; } 
    } 

    private Singleton() 
    { 
     // perform initialization logic 
     this.SomeValue = 5; // pick some arbitrary number 
    } 

    private Singleton(Singleton instance) 
    { 
     // perform cloning logic here to make "this" a clone of "instance" 
     this.SomeValue = instance.SomeValue; 
    } 

    public int SomeValue { get; set; } 

    public void DoSomething() 
    { 
     Console.WriteLine("Singleton.DoSomething: " + this.SomeValue); 
     // ... 
    } 
} 


class MainClass 
{ 
    private static IFactory<Singleton> _SingletonFactory; 

    public static IFactory<Singleton> SingletonFactory 
    { 
     get { return _SingletonFactory; } 
     set { _SingletonFactory = value; } 
    } 

    public Singleton Singleton { get; private set; } 

    public MainClass() 
    { 
     this.Singleton = SingletonFactory.CreateInstance(); 
    } 

    public void DoWork() 
    { 
     Console.WriteLine("MainClass.DoWork"); 
     this.Singleton.DoSomething(); 
     // ... 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     // you could either use the "First one wins" approach 
     MainClass.SingletonFactory = Singleton.GetFactoryFirstOneWins(); 

     // or use the "Indirect assignment" approach 
     Singleton.AssignFactories(); 

     // create two separate MainClass instances 
     MainClass mc1 = new MainClass(); 
     MainClass mc2 = new MainClass(); 

     // show that each one utilizes a Singleton cloned from Singleton.MainInstance 
     mc1.DoWork(); 
     mc2.DoWork(); 

     // updating mc1.Singleton.SomeValue does not affect any other instances of MainClass 
     mc1.Singleton.SomeValue = 7; 
     mc1.DoWork(); 
     mc2.DoWork(); 

     // updating Singleton.MainInstance.SomeValue affects any new instances of MainClass, but not existing instances 
     Singleton.MainInstance.SomeValue = 10; 
     MainClass mc3 = new MainClass(); 
     mc1.DoWork(); 
     mc2.DoWork(); 
     mc3.DoWork(); 
    } 
} 
+0

感謝您的解決方案。儘管我最終沒有使用這種解決方案,但間接分配技巧讓我想到了另一種設計解決方案。好主意,謝謝! – kateroh 2010-10-20 18:12:06

2

你可以簡單地在你的類中使用帶有私有靜態字段的Singleton模式。

像這樣:

class Singleton 
{ 
    private static Singleton _mainInstance = new Singleton(); 
    private Singleton() { } 
    public void Clone() {..} 

    public static Singleton MainInstance 
    { 
     return _mainInstance; 
    } 
} 

你將有你的存儲類的_mainInstance靜態字段裏面你唯一的實例,就不可能創造任何其他實例。

+0

我在方法和屬性中添加了'static'。我知道如何寫一個signleton,那不是原來的問題。我希望整個庫中只有一個類能夠實例化第一個實例。 – kateroh 2010-10-20 16:24:21

0

單例模式意味着只有一個該類的實例。如果你的類有某種克隆方法,那麼每個人都可以克隆這個實例。所以我看不到你的問題。

您的單例執行幾乎是正確的,只有_mainInstanceMainInstance需要爲static

+0

我添加了「靜態」,這是我的錯誤。克隆方法與原始問題無關 - 如何使該單例的第一個實例由解決方案中的1和1類創建。所以只有一個輸入點 - 你可以通過MainClass獲得這個實例,負責創建一個或者唯一的實例,或者你得到null。 – kateroh 2010-10-20 16:27:36

+0

你可以讓Singleton成爲Main的一個私有內部類,並讓Singleton實現一個公開的可見接口,它在任何地方都可見 – codymanix 2010-10-20 16:41:01

+0

但是你的問題沒有多大意義。如果Singleton每次都返回相同的實例,爲什麼只有你的MainClass應該被允許調用它呢?你害怕發生什麼? – codymanix 2010-10-20 16:43:12

1

您可以使用內部的構造函數只有在其裝配其他類使一個類實例化的:

class InternalInstantiation { 
    internal InternalInstantiation() {} 
    public void Clone() {} 
} 

class MainClass { 
    private InternalInstantiation _instance = 
    new InternalInstantiation(); 
} 

此外,您還可以嵌套在另一個內部類實例化一個類有私有構造函數。

class PrivateInstantiation { 
    private PrivateInstantiation() { } 
    public void Clone() {} 

    public class MainClass { 
    private PrivateInstantiation _instance = 
     new PrivateInstantiation(); 
    } 
} 

您還可以創建私有實例化的類中的主類注入它的一個實例(沒有其他類可以使用)方案:

public class MainClass { 
    internal PrivateInstantiation PrivateInstantiation { get; set; } 
    public MainClass() { 
    PrivateInstantiation.CreateAndSet(this); 
    } 
} 

class PrivateInstantiation { 
    private PrivateInstantiation() { } 
    public void Clone() {} 
    public static void CreateAndSet(MainClass mc) { 
    mc.PrivateInstantiation = new PrivateInstantiation(); 
    } 
} 

請注意,我沒有打電話你的班級是一個單身人士,因爲Clone方法的出現似乎並沒有使它成爲一個單身人士。

相關問題