如何设计一个只能由1个类实例化的Singleton

时间:2010-10-20 15:58:31

标签: c# singleton

我想设计一个类似于单例的类,就像该类的单个主实例一样,但主实例也可以有多个克隆。只允许1个类创建主实例,其他人都可以创建克隆。这样的事情(c#):

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的朋友来实现。

6 个答案:

答案 0 :(得分:2)

您可以在类中使用Singleton模式和私有静态字段。

像这样:

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

     public static Singleton MainInstance
     {
         return _mainInstance;
     }
}

您的唯一实例将存储在类的_mainInstance静态字段中,并且无法创建任何其他实例。

答案 1 :(得分:2)

以下是一个完整的工作实现,演示了实现所需内容的两种可能方法。

两种方法均采用工厂概念;由于Singleton的构造函数是私有的,因此只有嵌套的Factory类才能创建Singleton类的新实例。由于嵌套的Factory类本身是私有的,因此获取工厂实例的唯一方法是通过Singleton.GetFactoryFirstOneWins方法(“First one wins”方法)或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();
    }
}

答案 2 :(得分: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方法的存在似乎不会使其成为单身。

答案 3 :(得分:1)

答案 4 :(得分:0)

单例模式意味着那个类只有一个实例。如果你的类有某种克隆方法,那么每个人都能够克隆这个实例。所以我看不出你的问题。

您的单身人员实施几乎是正确的,只有_mainInstanceMainInstance需要static

答案 5 :(得分:0)

Monostate Pattern这样的东西?虽然这些实例都具有相同的状态,但这可能不是您想要的。