我正在尝试以正确的方式学习OOP和OOD原则。我想对Liskov替换原则及其PRE和POST条件做一些澄清。我在这里阅读了一些主题,http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod和其他地方的一些文章。
我已经编写了一个简单的基类和几个示例子类,我对其中的前置和后置条件进行了假设,我想知道它们是否正确。 注释行是我的想法:它是否违反了PRE和POST条件。
public abstract class BaseClass
{
public virtual int GetResult(int x, int y)
{
if (x > 10 && y < 20)
{
return y - x;
}
throw new Exception();
}
}
public class LSPExample1 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE: weakened pre condition is ok
if (x > 10 && y <= 15)
{
// POST: Is it ok? because the available result range is narrowed by y <= 15
return y - x;
}
throw new Exception();
}
}
public class LSPExample2 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE: Same as base - OK
if (x > 10 && y < 20)
{
// POST: I assume it's bad because of parameters place changed in substraction ?
return x-y;
}
throw new Exception();
}
}
public class LSPExample3 : BaseClass
{
public override int GetResult(int x, int y)
{
// PRE Condition is bad (Strenghtened) because of (X >5) and (Y>20) ?
if (x > 5 && y > 20)
{
// POST condition is ok because base class do substraction which is weaker than multiplication ?
return x * y;
}
throw new Exception();
}
}
我非常感谢你的时间
答案 0 :(得分:5)
这是您可以实际访问来源的精彩情况之一。 Barbara Liskov的原始论文可用且易于阅读且易于阅读。 http://csnell.net/computerscience/Liskov_subtypes.pdf
您显示的所有四个GetResult
方法都接受两个整数作为输入,并返回一个整数或抛出异常。在这方面,它们都具有相同的行为,因此可以说LSP完全满足。如果没有显式的前/后条件或不变量,那么关于代码的其他任何事情都无法说明。
你的例子中缺少的是合同。来自其来电者GetResult
需要的内容是什么保证会产生什么?
例如,如果合同保证返回值等于y-x,那么示例2和3将失败合同,从而破坏LSP。但是,如果唯一的保证是返回值是Int或Exception,那么它们都会通过。
如果合同保证在x&lt; = 10 ||时将抛出异常y> = 20然后实施例1&amp; 3破LSP。如果唯一的保证是该方法将返回一个Int或抛出一个异常,那么它们都满足它。
代码无法告诉您保证是什么,它只能告诉您希望代码执行。
由于我获得了大量的投票,我将添加一个示例(伪代码):
class Line {
int start
int end
int length() { return end - start } // ensure: length = end - start
void updateLength(int value) {
end = start + value
// ensure: this.length == value
}
}
两个函数中的每一个中的“ensure”子句都是关于调用函数后Line对象状态的保证。只要我满足子类中的保证,我的子类就会符合LSP。例如:
class Example1: Line {
void updateLength(int value) {
start = end - value
}
}
以上内容满足LSP。
如果Line的updateLength函数也有一个“this.start unchanged”的ensure子句,那么我的子类将不满足LSP。