所以我有一个关于检查对象是否使用特定构造函数实例化的问题。我有一个名为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的构造函数是否是上面的方法,否则该方法将无法正常运行并抛出某种异常,如果它不是'吨。做这个的最好方式是什么?非常感谢提前!
答案 0 :(得分:4)
这是Liskov Substitution Principle重要性的一个很好的例子。我非常喜欢this answer中使用的图像。
如果你的类有多个构造函数,并且你的方法的成功取决于调用了哪个构造函数,那么你有很多选择。
这里的主要问题是你的对象状态似乎取决于调用哪个构造函数;这不是最好的设计技术,因为它会导致整个班级的状态检查激增,无论您如何呈现您的实施。
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并设置其他变量?他们如何知道使用哪个界面?这就是为什么使它成为函数的一个条件,使用和维护都要简单得多。
将来也会使这门课程变得困难。如果方法的成功依赖于首先调用其他几个方法或构造函数,那么重构和更改此逻辑也会强制所有客户端也进行更改。
答案 1 :(得分:1)
您可以在课程中设置public
boolean property
,并在特定的constructor
中设置true
。此属性的默认值可以是false
。
因此,如果对象是obj1,则可以在调用函数之前检查此布尔值。
if(obj1.public_property)
// do function call
这只是一个解决方案。可能有比这更好的解决方案。
答案 2 :(得分:0)
快速解决方案(不好)将使用一个标志来指示调用哪个构造函数 - 稍后在代码中的任何位置检查它。
你需要的是F#中的Discriminated Unions。但是因为我们在C#中没有,所以你应该将你的类抽象为interface
,然后为该接口提供不同的具体实现。
现在您可以使用方法重载(针对每个具体实现)来决定使用哪个具体实现。