1

所以我有一个关于检查对象是否使用特定构造函数实例化的问题。我有一个名为 SearchWithTwoLevelCore 的类,它是搜索引擎的一部分。它有一个这样的构造函数:

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp)
    {
        //Initialize the two levels.
        S=s;
        lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0));
        lvl1 = SizeBoundedQueryCache(lvl2, 10);


    }

其中 S、lvl1 和 lvl2 都是在类中声明的私有字段,其中包含其他公共类的对象。然后我有一个要运行的公共方法,它位于 SearchWithTwoLevelClass 中,但首先我想检查用于制作 SearchWithTwoLevelCache 的构造函数是否是上面的构造函数,否则该方法将无法正常运行并抛出某种异常,如果不是吨。做这个的最好方式是什么?提前非常感谢!

4

3 回答 3

4

这是Liskov 替换原则重要性的一个很好的例子。我非常喜欢这个答案中使用的图像。

如果您的类有多个构造函数,并且方法的成功取决于调用了哪个构造函数,那么您有多种选择。

这里的主要问题是您的对象状态似乎取决于调用哪个构造函数;这不是最好的设计技术,因为它会导致整个班级的状态检查激增,无论您如何展示您的实现。

1) 将你的对象重构为更小的对象

这里的想法是你的构造函数应该只需要类需要运行的数据。如果您有多个构造函数,每个构造函数都需要不同数量的参数和数据,那么可以说这个类实际上代表了几个不同的对象。

2) 执行方法上的数据要求。

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp)
{
    //Initialize the two levels.
    S=s;
    lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0));
    lvl1 = SizeBoundedQueryCache(lvl2, 10);
}

可以说,这个状态实际上并不是类本身所需要的,因为如果它实际上是一个函数的先决条件,那么就让它成为函数本身的一个要求。这消除了歧义。

因此,您的班级可能会变成:

public SearchWithTwoLevelCache(ISearchCore s)
{
  S = s;
} 

public Whatever PerformTwoLevelSearch(ICurrentTimeProvider tp) { }

例如。

这里的想法是仅在构造函数中提供整个类的状态绝对需要的数据。

当然,您可以在方法级别实现检查并抛出异常,但是对于使用您的类的人来说,这可能会非常令人沮丧。他们怎么知道要调用函数 1,他们必须调用构造函数 2 并设置其他变量?他们怎么知道要使用哪个接口?这就是为什么使它成为函数的条件更易于使用和维护的原因。

这也将使将来扩展这个类变得困难。如果方法的成功依赖于首先调用几个其他方法或构造函数,那么重构和更改此逻辑也会迫使所有客户端也进行更改。

于 2013-06-24T08:52:50.877 回答
1

您可以public boolean property在类中设置 a ,并在特定的constructor情况下进行设置true。该属性的默认值可以是false

所以如果对象是obj1,你可以在调用函数之前检查这个布尔值。

if(obj1.public_property)
     // do function call

这只是一个解决方案。可能有比这更好的解决方案。

于 2013-06-24T08:47:44.623 回答
0

快速解决方案(不好)将使用一个标志来指示调用哪个构造函数 - 通过稍后在代码中的任何地方检查它。

您实际上需要的是F# 中的可区分联合。但是由于我们在 C# 中没有 then,因此您应该将您的类抽象为interface然后为该接口提供不同的具体实现。

现在您可以使用方法重载(针对每个具体实现)来决定使用哪个具体实现。

于 2013-06-24T08:53:41.140 回答