首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这个类层次结构违反了LSP?

为什么这个类层次结构违反了LSP?
EN

Stack Overflow用户
提问于 2021-11-16 03:05:04
回答 1查看 67关注 0票数 1

下面是在线教程(https://code-maze.com/liskov-substitution-principle/)的代码:

代码语言:javascript
复制
// 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();
}

然后我们就可以:

代码语言:javascript
复制
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原则,我们需要这样做:

代码语言:javascript
复制
// 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原则?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-30 21:20:24

您的version 1与独立于示例程序的LSP不兼容。

您可以“将子实例存储到父变量”这一事实是一个由C#支持的子类型的语法概念。LSP提供了子类型的行为概念,坚持在任何子类中保留超类型的意义(语义)。

version 1中,超类Calculate方法计算所有数字,但子类中只计算偶数。这使得子类的行为与超类不一致。

在与LSP兼容的version 2中,通过添加一个没有任何行为的单独类,并在两个独立的子类型中对它进行两次扩展,可以避免这一点。这是符合LSP的。

如果您正在寻找一个想要保持超类行为的示例,那么可以考虑一个类,它除了计算之外还会做一些额外的事情,例如,在LoggingCalculator中,Calculate方法首先调用超类方法(保持相同的行为),然后通过在某个地方记录结果来扩展它。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69983302

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档