C# class 设计 - 实例独立信息

C# class design - instance independent information

我遇到了 class 设计困境:我有一个通用基础 class 和多个派生 class 。基础是一个 CRTP class 提供通用功能,其中一些功能需要 inherited-class-specific 数据。因此,基础 class 是抽象的,child classes 必须实现某些 "provider" 方法。例如:

public abstract class Base<T> where T : Base<T>, new() {
    private static T reference = new T();

    public static int Foo => reference.GetFoo();

    public static string Bar => reference.GetBar();

    protected abstract int GetFoo();

    protected abstract string GetBar();

    // ...
}

问题是信息不是 instance-specific,应该可以从通用参数访问。所以使用上面的例子,这个方法可以在另一个 class:

public void ComputeSomething<T>() where T : Base<T>, new() {
    int foo = Base<T>.Foo;

    // ...
}

或者如果 child class 已知:ChildClass.Foo

这行得通,但总的来说解决方案感觉 "dirty",因为我讨厌用类型信息弄乱每个实例,并且基础 class 必须保留一个 reference 实例(如何sub class 可以在它的基础上创建 class 仍然让我有点费解,而且通常看起来是个坏主意)。我会将信息放在缓存或工厂或其他东西中,但我无法控制所有 child classes,因此系统必须是可扩展的。我查看了使用属性,但没有办法(据我所知)强制某些属性在编译时出现。真的,我觉得我需要静态接口或静态抽象成员,但 C# 没有这些。

所以我的问题是:这种问题一般是怎么解决的?

I'm starting to think I need a separate provider class or something

这就是答案。每当我遇到这些复杂的通用继承场景时,问题是我通过继承而不是组合来组合 classes。这就是为什么您会听到原则“favor composition over inheritance.

无论派生的classes需要从基础class得到什么,它真的需要通过继承获得,还是可以通过创建一个单独的class并依赖于它?

如果多个派生的 class 将依赖于相同的 class(这暗示了继承的情况),那么也许可以将单独的 class 依赖构建到基础中class。但它仍然是一个单独的class。派生的 classes 继承了对它的 依赖性 而不是继承实际的方法和属性。

我发现,当重构是继承的结果时,继承更有效,也许是一种重构重复代码的方法(或在它开始之前停止它。)当我开始时认为我要要预先重用代码,很可能最终会变得过于复杂。也许是因为我们实际上仍在编写 classes 并确定它们将如何工作。试图建立一个层次结构迫使我们预先假设太多,然后放弃设计是令人沮丧的。当事后重构或我们考虑添加可能重复代码的新 class 时,它的效果更好。

但即使在我添加新的 classes 并且不想重复代码的情况下,我也可能会考虑将重复的代码重构为它自己的 class 而不是使用新的代码class继承现有的。