在抽象类的构造函数中通过虚拟成员分配只读字段

时间:2013-09-24 15:16:47

标签: c# .net oop design-patterns

我知道在SO上已经提到了类似的问题,但具体来说,我的问题涉及通过在抽象类的构造函数中调用虚拟成员来设置readonly字段的方案。

考虑以下抽象类:

public abstract class FooBase
{
    private readonly IDictionary<string,object> _readonlyCache;

    protected abstract IDictionary<string,object> SetCache();

    protected FooBase()
    {
        _readonlyCache = SetCache();
    }
}

问题:

1)这是不是很糟糕的设计?

2)有更好的设计吗?

我知道您可以将FooBase的实施者声明为sealed,这样可以确保只调用SetCache()的正确实现。我不喜欢的是,强制执行无法将实施者标记为sealed。任何建议都非常受欢迎。

2 个答案:

答案 0 :(得分:4)

如果可能的话,肯定要避免这种情况 - 在构造函数中调用虚方法总是有点臭,因为在子类执行初始化之前你将执行代码 - 它的构造函数体不会被执行。无论子类是否密封,都是如此;你处于一个根本恶劣的境地。

您可能需要考虑使子类构造函数将缓存传递给构造函数:

public abstract class FooBase
{
    private readonly IDictionary<string,object> _readonlyCache;

    protected FooBase(IDictionary<string,object> cache)
    {
        _readonlyCache = cache;
    }
}

这样 direct 子类就可以决定做什么 - 例如,它可能是抽象的,并从进一步派生的类中获取缓存,或者它可能构造自己的。

答案 1 :(得分:1)

1)是的,这是糟糕的设计,因为你不能强迫实施者被密封。 (我不明白你怎么能合理地强制对别人的代码做出那种设计决定;你不能控制别人的抽象层次。)

2)是:例如,使ReadOnlyCache属于抽象属性或非抽象属性,并在第一次使用时调用抽象方法以获取它的值:

private readonly IDictionary<string,object> _readonlyCache;

private IDictionary<string,object> ReadOnlyCache
{
    get
    {
        return _readonlyCache ?? _readonlyCache = GetEmptyCache();
    }
}

protected abstract IDictionary<string,object> GetEmptyCache();