簡體   English   中英

具有多個子類的抽象單例繼承

[英]Abstract singleton inheritance with multiple sub-classes

與給出的答案繼續在這里 ,有什么辦法可以讓MyChildSingleton是抽象的,然后讓它的子類定義了自己的構造函數? 我想做的一個例子:

public abstract class SingletonBase<T> 
    where T : SingletonBase<T>, new()
{
    private static T _instance = new Lazy<T>(() => new T());
    public static T Instance
    {
        get
        {                
            return _instance;
        }   
    }
}

public abstract class DefaultConfigData: SingletonBase<DefaultConfigData>
{
    // This class won't compile since it's abstract, and SingletonBase<T>
    // has a new() restriction on T
    // Also, this class is immutable and doesn't change state
    public virtual string SomeData { get; } = "My Default Data String";

    public virtual double MoreData { get; } = 2.71;

    public virtual double SomeFunction(double num)
        { return num + 2*MoreData; }
    public DefaultConfigData() { ; /* nothing to do here */ }

    // Another 50 or so default values/functions...
    // enough to be tedious to redefine in multiple places,
    // and adding a constructor that takes every value would be ridiculous.
    // It would be possible to encapsulate this data, but I'm not
    // yet sure how this should be done, so I haven't gone there yet
}

public class SpecificConfigData1: DefaultConfigData
{
    public override string SomeData { get; } = "A Different String";
    public SpecificConfigData1() { ; /* nothing to do here */ }
}

public class SpecificConfigData2: DefaultConfigData
{
    public override double MoreData { get; } = 3.14;
    public SpecificConfigData2() { ; /* nothing to do here */ }
}

// Downstream developers may need to define additional ConfigData classes

public class Library
{
    public static double doSomething(DefaultConfigData data) { return data.MoreData + 2.0; }
}

public class Program
{
    private readonly DefaultConfigData data;
    public Program(bool choice)
    {
        data = (choice) ? SpecificConfigData1.Instance : SpecificConfigData2.Instance;
    }

    public static void Main()
    {
        Program prog = new Program(/*run-time user input here*/);
        Console.PrintLine(Library.doSomething(prog.data));
    }
}

使用單例模式似乎是個好主意,因為對於每個特定的子類,數據只需要存在於一個地方,並且由於它是不可變的,因此可以避免大多數與單例相關的問題(全局可變狀態等)。 在抽象基類中提供單例功能將避免放置私有實例和公共get屬性的樣板,這是我現在在每個子類中所做的。 這確實不是一個繁重的要求,我敢肯定我可以接受。

我不想使DefaultConfigData及其數據靜態,因為那樣我就不能繼承它,並且我的庫函數知道如何與之交互(不支持C#中的元類)。 另外,我不想使用接口,因為太多的功能是共享的,我無法在接口中定義。

如果我要嘗試的方法無法實現,或者另一種方法更簡單,我也歡迎您提出其他方法的評論。 我知道工廠模式也可以在這里工作,這是我最終打算嘗試的方法。

最后,為什么這甚至是個問題? 如果抽象類的任何子類也都滿足new(),為什么不做出讓抽象類滿足new()要求的決定呢?

請注意,我的“用戶”是其他內部開發人員/我將來的自己。 源代碼通常是可交付的,並且在這種環境下將檢查推送到運行時是可以的。

我能想到的最簡單的解決方案是使用工廠模式。 另一個解決方案是您需要保持DefaultConfigData類的通用性,例如:

public abstract class DefaultConfigData<T>: SingletonBase<T>
    where T : DefaultConfigData<T>, new()
{ }

問題是當您想在任何地方使用DefaultConfigData ,必須使該方法或類通用,例如doSomething方法:

public static double doSomething<T>(DefaultConfigData<T> data)
    where T : DefaultConfigData<T>, new()
{
    return data.MoreData + 2.0;
}

正如您所猜測的那樣,這確實很煩人。 因此,回到工廠模式:

public static class MyFactory<T>
{
    private static Lazy<T> _instance = new Lazy<T>(CreateUsingReflection);
    public static T Instance
    {
        get
        {
            return _instance.Value;
        }
    }

    private static T CreateUsingReflection()
    {
        BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        ConstructorInfo ctor = typeof(T).GetConstructor(flags, null, Type.EmptyTypes, null);
        return (T)ctor.Invoke(null);
    }
}

而且,您可以像這樣使用它:

SpecificConfigData1 scd1 = MyFactory<SpecificConfigData1>.Instance;

請注意,您的任何類都無需繼承MyFactory 只要擁有無參數構造函數,您就可以自由創建從任何東西(或什么都不繼承)繼承的類。 你可以限制TMyFactory<T>使用where T : new()在這種情況下,你會得到編譯時保證該類支持參數的公共構造函數,並且可以通過創建僅使用類避免反光new T() 沒有new()限制,它可以使用私有構造函數創建單例,但是您會丟失編譯時檢查是否存在無參數構造函數的信息。

實際上,還有另一種解決方案。 它要復雜得多,但是如果您充分利用它,它會非常強大:一個IoC容器,例如AutofacUnity和許多其他容器。 這些可以幫助管理您的實例,以便您可以指定應該為單例的類型。 我不會討論如何使用它,因為那是一個完全不同的主題,並且將需要多個段落來解釋基礎知識。

暫無
暫無

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

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