下面是在线教程(https://code-maze.com/liskov-substitution-principle/)的代码:
// version 1
public class SumCalculator
{
protected readonly int[] _numbers;
public SumCalculator(int[] numbers)
{
_numbers = numbers;
}
public virtual int Calculate() => _numbers.Sum();
}
public class EvenNumbersSumCalculator: SumCalculator
{
public EvenNumbersSumCalculator(int[] numbers)
:base(numbers)
{
}
public override int Calculate() => _numbers.Where(x => x % 2 == 0).Sum();
}然后我们就可以:
class Program
{
static void Main(string[] args)
{
var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 };
SumCalculator sum = new SumCalculator(numbers);
Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}");
Console.WriteLine();
SumCalculator evenSum = new EvenNumbersSumCalculator(numbers);
Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}");
}
}所以我们可以将子实例(new EvenNumbersSumCalculator(numbers))存储到父变量(SumCalculator evenSum )中,所以上面的代码符合Liskov原则,不是吗?
但是教程说第1版不符合Liskov原则,我们需要这样做:
// version 2
public abstract class Calculator
{
protected readonly int[] _numbers;
public Calculator(int[] numbers)
{
_numbers = numbers;
}
public abstract int Calculate();
}
public class SumCalculator : Calculator
{
public SumCalculator(int[] numbers)
:base(numbers)
{
}
public override int Calculate() => _numbers.Sum();
}
public class EvenNumbersSumCalculator: Calculator
{
public EvenNumbersSumCalculator(int[] numbers)
:base(numbers)
{
}
public override int Calculate() => _numbers.Where(x => x % 2 == 0).Sum();
}
class Program
{
static void Main(string[] args)
{
var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 };
Calculator sum = new SumCalculator(numbers);
Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}");
Console.WriteLine();
Calculator evenSum = new EvenNumbersSumCalculator(numbers);
Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}");
}
}我不明白为什么版本1不符合Liskov原则?
发布于 2021-11-30 21:20:24
您的version 1与独立于示例程序的LSP不兼容。
您可以“将子实例存储到父变量”这一事实是一个由C#支持的子类型的语法概念。LSP提供了子类型的行为概念,坚持在任何子类中保留超类型的意义(语义)。
在version 1中,超类Calculate方法计算所有数字,但子类中只计算偶数。这使得子类的行为与超类不一致。
在与LSP兼容的version 2中,通过添加一个没有任何行为的单独类,并在两个独立的子类型中对它进行两次扩展,可以避免这一点。这是符合LSP的。
如果您正在寻找一个想要保持超类行为的示例,那么可以考虑一个类,它除了计算之外还会做一些额外的事情,例如,在LoggingCalculator中,Calculate方法首先调用超类方法(保持相同的行为),然后通过在某个地方记录结果来扩展它。
https://stackoverflow.com/questions/69983302
复制相似问题