簡體   English   中英

抽象基類強制每個派生類為Singleton

[英]Abstract base class to force each derived classes to be Singleton

如何創建一個抽象類來強制每個派生類為Singleton? 我用C#。

這是行不通的,因為單身人士需要一個靜態訪問,而不能被強制。

for singletonimplemention + examples請參閱: 在C#中實現Singleton模式

如果要編譯時間檢查,則無法進行此操作。 通過運行時檢查,您可以執行此操作 它不漂亮,但它是可能的。 這是一個例子:

public abstract class Singleton
{
    private static readonly object locker = new object();
    private static HashSet<object> registeredTypes = new HashSet<object>();

    protected Singleton()
    {
        lock (locker)
        {
            if (registeredTypes.Contains(this.GetType()))
            {
                throw new InvalidOperationException(
                    "Only one instance can ever  be registered.");
            }
            registeredTypes.Add(this.GetType());
        }
    }
}

public class Repository : Singleton
{
    public static readonly Repository Instance = new Repository();

    private Repository()
    {
    }
}

這是一種(丑陋的)方式。 它可能會被簡化和改進,但這是我第一次采用它。

我們的想法是首先使基類成為通用抽象類(如上面的注釋中所述),但類型參數被約束為從基類本身派生。 這允許基類處理派生類型的單例實例。 請注意,所有派生類都應該密封,就像任何單例類一樣。

接下來,允許使用受保護的構造函數,但是需要接受特殊類SingletonKey的實例,SingletonKey是一個修改過的單例。 派生類可以訪問SingletonKey類定義,但基類保留對唯一允許的實例的私有控制,從而保留對所有派生對象的構造。

第三,基類需要能夠調用派生類的構造函數,但這有點棘手。 如果您嘗試調用派生的鍵控構造函數,編譯器將會抱怨,因為它不能保證存在。 解決方案是添加派生類必須初始化的靜態委托。 因此任何派生類都需要提供一個簡單的初始化方法。 在嘗試首次在代碼中訪問實例之前,應該顯式調用此初始化方法,否則將導致運行時錯誤。

public abstract class Singleton<T> where T : Singleton<T>
{
    protected Singleton(SingletonKey key) { }
    private static SingletonKey _key;
    private static SingletonKey Key
    {
        get
        {
            if (_key == null) SingletonKey.Initialize();
            return _key;
        }
    }
    protected class SingletonKey
    {
        private SingletonKey()
        {
        }
        public static void Initialize()
        {
            if (_key == null)
            {
                _key = new SingletonKey();
            }
        }
    }

    protected static Func<SingletonKey, T> Creator;
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null) instance = Creator(Key);
            return instance;
        }
    }
}

public class MySingleton : Singleton<MySingleton>
{
    public string Name { get; set; }
    public static void Initialize()
    {
        Creator = (key) => new MySingleton(key);
    }
    protected MySingleton(SingletonKey key) : base(key)
    {
    }
}

Singleton意味着擁有私有構造函數。 但是你知道私人成員不能被繼承。 在C ++中有模板,因此您可以從模板類創建單例。 在C#中,沒有模板,所以你必須為你想要的每個單獨編寫自己的私有構造函數。

java或C#中的類不是“第一類”。 子類的靜態部分不能由子類繼承或覆蓋。 有關詳細信息,請參閱此答案 另外,你沒有元類的概念。

在Smalltalk或Ruby等語言中,您可以定義一個新的元類Singleton ,它定義了一個方法getInstance 然后,您可以將ClassAClassB定義為Singleton元類的實例。 然后,這兩個類自動公開一個方法getInstance ,該方法可用於創建實例objectAobjectB 那不是很酷嗎? 好吧,在實踐中你不經常使用元類,而單例實際上是它們的唯一用法,它是有意義的並且我知道。

我相信我試圖實現類似的東西,即在一組類上強制執行通用接口和單例模式。 這是我的解決方案:

// Common interface of my singleton classes
public interface IMySingletonClass
{
    string ValueGetter();

    void ValueSetter(string value);
}

// Generic abstract base class
public abstract class Singleton<T>: IMySingletonClass
{
    private static readonly object instanceLock = new object();
    private static T instance; // Derived class instance

    // Protected constructor accessible from derived class
    protected Singleton()
    {
    }

    // Returns the singleton instance of the derived class
    public static T GetInstance()
    {
        lock (instanceLock)
        {
            if (instance == null)
            {
                instance = (T)Activator.CreateInstance(typeof(T), true);
            }
            return instance;
        }
    }

    // IMySingletonClass interface methods
    public abstract string ValueGetter();

    public abstract void ValueSetter(string value);
}

// Actual singleton class
public class MySingletonClass : Singleton<MySingletonClass>
{
    private string myString;

    private MySingletonClass()
    {
        myString = "Initial";
    }

    public override string ValueGetter()
    {
        return myString;
    }

    public override void ValueSetter(string value)
    {
        myString = value;
    }
}

這是一個簡單的測試:

class Program
{
    static void Main(string[] args)
    {
        MySingletonClass r1 = MySingletonClass.GetInstance();
        Console.WriteLine("R1 value = {0}", r1.ValueGetter());
        r1.ValueSetter("Changed through R1");
        MySingletonClass r2 = MySingletonClass.GetInstance();
        Console.WriteLine("R2 value = {0}", r2.ValueGetter());

        Console.ReadKey();
    }
}

請注意,如果您只需要基本的“模板”,則可以輕松地從通用抽象單例類中刪除公共接口。

這里是我對Singleton繼承的實現:

using System;
using System.Reflection;

namespace Mik.Singleton
{
    class Program
    {
        static void Main()
        {
            //You can not create an instance of class directly
            //Singleton1 singleton1 = new Singleton1();

            Singleton1 singleton1 = Singleton1.Instance;
            Singleton2 singleton2 = Singleton2.Instance;

            Console.WriteLine(singleton1.Singleton1Text);
            Console.WriteLine(singleton2.Singleton2Text);

            Console.ReadLine();
        }
    }

    public class SingletonBase<T> where T : class
    {
        #region Singleton implementation

        private static readonly object lockObj = new object();
        private static T _instance;

        protected SingletonBase() { }

        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (lockObj)
                    {
                        if (_instance == null)
                            _instance = CreateInstance();
                    }
                }
                return _instance;
            }
        }

        private static T CreateInstance()
        {
            ConstructorInfo constructor = typeof(T).GetConstructor(
                            BindingFlags.Instance | BindingFlags.NonPublic,
                            null, new Type[0],
                            new ParameterModifier[0]);

            if (constructor == null)
                throw new Exception(
                    $"Target type is missing private or protected no-args constructor: {typeof(T).FullName}");
            try
            {
                T instance = constructor.Invoke(new object[0]) as T;

                return instance;
            }
            catch (Exception e)
            {
                throw new Exception(
                    "Failed to create target: type=" + typeof(T).FullName, e);
            }
        }

        #endregion Singleton implementation
    }

    public class Singleton1 : SingletonBase<Singleton1>
    {
        private Singleton1() { }

        public string Singleton1Text { get; } = "Singleton1Text value";
    }

    public class Singleton2 : SingletonBase<Singleton2>
    {
        private Singleton2() { }

        public string Singleton2Text { get; } = "Singleton2Text value";
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM