封装dependency/coupling和静态数据列表的层级

Encapsulate dependency/coupling and hierachy of static data list

抱歉标题,我真的不知道如何称呼这个问题。我有一个摘要 class,它描述了一些数据的接口 collection。我想检索由此派生的所有 classes 的实例列表,而不会乱扔基础 class 或使用它的代码以及对新类型名称的引用。实际上,我希望能够添加基础的新派生 classes,其余代码应该不受影响。

也许一些代码可以帮助说明问题:

public abstract class BaseData
{
    public static List<BaseData> getCollection()
    {
        return collection;
    }

    static private List<BaseData> collection = new List<BaseData>();

    // the actual part of the interface.
    public abstract int[] getSomeData();

    protected BaseData()
    {
        // when some derived class is statically created, they get added to the static list.
        collection.Add(this);
    }
}

然后我可以像这样使用界面:

// some actual code file:
class App
{
    public App()
    {
        foreach(var dataimpl in BaseData.getCollection())
        {
            //.. do something here.
            var data = dataimpl.getSomeData();
        }
    }
}

想法是,我现在可以在另一个文件中向此数据 collection 添加新案例,而无需更改其他两段代码,如下所示:

// hidden implementation classes
class SomeImplementation1 : BaseData
{
    // register the class in the base class list
    static private SomeImplementation1 register = new SomeImplementation1();
    public override int[] getSomeData() { return null; }
    private SomeImplementation1() { }
}

class SomeImplementation2 : BaseData
{
    // register the class in the base class list
    static private SomeImplementation2 register = new SomeImplementation2();
    public override int[] getSomeData() { return null; }
    private SomeImplementation2() { }
}

用例很多,测试,数据等等。 但是, 的问题是 child classes 中的静态寄存器变量实际上并未实例化(因此,parent构造函数不是 运行,这反过来意味着 class 在 child class 被引用之前未在 collection 中注册 - 即静态在创建实例之前,初始化程序不会 运行。

这就要求我在列表中的某处引用 child classes,这违背了该系统的全部目的。 我的问题是,这是一种常见模式吗 - 是否有现有的解决方案或某种程度上与此类似的实现 - 或者可以以某种方式修复此代码?

谢谢

摆脱 "abstract class which describes the interface" 并使用实际界面。

interface IHaveData
{
    int[] getSomeData();
}

现在,您可以自由地按照自己的意愿实施注册。这是适合您的初始代码的一种简单方法:

class BaseData
{
    private static readonly List<IHaveData> collection = new List<IHaveData>();

    public static IEnumerable<IHaveData> getCollection()
    {
        return collection;
    }

    public static void Register(IHaveData instance)
    {
        collection.Add(instance);
    }
}

class SomeImplementation1 : IHaveData
{
    private static readonly SomeImplementation1 registration = new SomeImplementation1();

    private SomeImplementation1()
    {
        BaseData.Register(this);
    }

    public int[] getSomeData() { return null; }
}

class SomeImplementation2 : IHaveData
{
    private static readonly SomeImplementation2 registration = new SomeImplementation2();

    private SomeImplementation2()
    {
        BaseData.Register(this);
    }

    public int[] getSomeData() { return null; }
}

更新 您将需要某种容器并手动注册您的实例或使用反射来实例化您的实例并将它们添加到容器中。

class SomeImplementation1 : IHaveData
{
    public int[] getSomeData() { return null; }
}

class SomeImplementation2 : IHaveData
{
    public int[] getSomeData() { return null; }
}

手动注册(最安全,但您必须为每个新实施编辑注册)

class BaseData
{
    private static readonly List<IHaveData> collection = new List<IHaveData>
    {
        new SomeImplementation1(),
        new SomeImplementation2()
        //as you add more implementations, you'll need to add them here
    };

    public static IEnumerable<IHaveData> getCollection()
    {
        return collection;
    }
}

自动注册(不再编辑注册,但任何构造函数更改,您都会遇到运行时错误并且难以调试)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

class BaseData
{
    private static List<IHaveData> collection;

    public static IEnumerable<IHaveData> getCollection()
    {
        if (collection == null)
        {
            var types = Assembly.GetExecutingAssembly().GetTypes()
                .Where(type =>
                    type.IsClass &&
                    !type.IsAbstract && 
                    type.GetInterfaces().Any(i => i == typeof(IHaveData)));

            //All implementation must have the same constructor signature. In this case, a parameterless constructor.
            collection = new List<IHaveData>(types.Select(x => (IHaveData)Activator.CreateInstance(x)));
        }

        return collection;
    }
}