标签: liskov-substitution-principle

Java异常层次结构背后的基本原理

我发现Java的异常层次结构令人困惑.Throwable分为ErrorException,并RuntimeException继承自Exception.

  1. Error是一个未经检查的例外.为什么不从那时Error继承RuntimeException

  2. Exception是一个经过检查的例外 RuntimeException是一个未经检查的异常,但它继承自Exception.这不违反利斯科夫替代原则吗?

如果Throwable分为Exception(已检查)和RuntimeException(未经检查),并且Error会继承,那会不会更有意义RuntimeExeption

java inheritance exception-handling liskov-substitution-principle exception

6
推荐指数
1
解决办法
606
查看次数

阶级使用陷阱打破Liskov替代原则

在我最近工作的一个项目中,注意到一些接受属于层次结构的类的方法具有类似于以下的代码:

public void Process(Animal animal) {
    if(animal.GetType() == typeof(Dog)) {
        Console.WriteLine("We have a dog");
    }
    else {
        Console.WriteLine("not a dog");
    }
}
Run Code Online (Sandbox Code Playgroud)

好吧,这让我感到公然违反了LSP,因为现在如果你使用狗的子类,无论是在生产代码,单元测试模拟,还是作为依赖注入拦截器的一部分,这个代码将不会以相同的方式工作.我相信通过将条件更改为:可以轻松修复此特定方案:

  if (animal is Dog)
Run Code Online (Sandbox Code Playgroud)

这让我想到了:

是否有任何其他缺陷可以破坏客户端代码中的LSP?

UPDATE

只是为了澄清,我正在寻找在层次结构中使用类的代码中可能存在的缺陷.我知道并且我不是在寻找严重受限制的层次结构的问题 - (例如矩形 - 方形问题).我试图找出要查找的内容,以确保代码将支持动态模拟,拦截器,装饰类(例如LoggingDog),就像处理原始类一样.

通过答案和链接到目前为止,我可以看到唯一的缺陷是直接使用类的类型 - 即GetType()直接使用方法或通过其他技术.尽管这里有一些注释isas运算符,甚至在这种情况下转换为基类型也不会破坏LSP,因为子类将以与原始类相同的方式进行评估.

.net c# types dependency-injection liskov-substitution-principle

6
推荐指数
1
解决办法
537
查看次数

Square和Rectangle继承有什么问题?

我已经阅读了一些关于使Square成为Rectangle类的继承类的做法的一些文章,这说明它违反了LSP(Liskov替换原则).我仍然没有得到它,我在Ruby中做了一个示例代码:

class Rectangle
    attr_accessor :width, :height
    def initialize(width, height)
        @width = width
        @height = height
    end
end

class Square < Rectangle
    def initialize(length)
        super(length, length)
    end
    def width=(number)
        super(number)
        @height = number
    end

    def height=(number)
        super(number)
        @width = number
    end
end


s = Square.new(100)

s.width = 50

puts s.height
Run Code Online (Sandbox Code Playgroud)

谁能告诉我它有什么问题?

ruby oop liskov-substitution-principle

6
推荐指数
1
解决办法
2471
查看次数

C#返回类型协方差和Liskov替换原则

我正在尝试理解协方差和LSP.从这个问题我可以看出C#不支持返回类型协方差.然而Liskov替换原则对返回类型强加协方差.

这是否意味着在C#中应用这个原则是不可能的?还是我想念一些东西?

c# liskov-substitution-principle covariance solid-principles

6
推荐指数
1
解决办法
877
查看次数

IS-A和Liskov替代原则之间的区别?

我只是想知道IS-A(UML术语和OOP)和Liskov替换原则(LSP)之间是否存在差异?

实际上,两者都在谈论继承.那么实践中的主要区别是什么?

oop inheritance liskov-substitution-principle solid-principles

6
推荐指数
1
解决办法
698
查看次数

Liskov替换原理 - 重写方法示例

让我们说我们有这个非常微不足道的课程:

class A
{
    virtual int Function(int number)
    {
      return number;
    }
}

class B : A
{
    override int Function(int number)
    {
        return number + 1;
    }
}

class UseExample
{
    void Foo(A obj)
    {
        A.Function(1);
    }
}
Run Code Online (Sandbox Code Playgroud)

这个例子会违反LSP吗?如果是这样,你能给我一个不违反原则并使用不同实现的例子吗?

这个如何:

class B : A
{
    int variable;

    override int Function(int number)
    {
        return number + variable;
    }
}
Run Code Online (Sandbox Code Playgroud)

据我所知,使用变量"variable"会导致更强的前置条件,因此它违反了LSP.但是我不完全确定在使用多态时如何遵循LSP.

liskov-substitution-principle

5
推荐指数
1
解决办法
1014
查看次数

当"if else"/"instance of"不可避免时,除了使用访客模式之外,我们如何改进设计呢?

当我们的对象层次结构纯粹是语义的继承而不是行为的继承时,那么我们不可避免地需要在任何地方编写"instanceof"或"if/else"来进行运行时类型检查.

例如

如果我有一个对象层次结构

Class Function

Class Average extends Function

Class Sum extends Function

Class Max extends Function
Run Code Online (Sandbox Code Playgroud)

如果在这些类中有一个名为calculate()的方法,那么我们没有问题,我们可以利用多态性,这种设计满足LSP.

但是,如果由于某种原因我们不想将此calculate()方法添加到此层次结构中,则这些对象纯粹是对象无状态对象,只表示语义.

然后我们被迫在任何地方编写以下代码:

if (function instanceof Average)
//perform average
else if(function instanceof Sum)
//perform sum
else if(function instanceof Max)
//perform max
Run Code Online (Sandbox Code Playgroud)

上面的代码表明设计不好,因为你在任何地方编写这个代码,这个设计很脆弱,以后很难改变.我想如果数字函数是有限的并且函数的计算在一个地方,这可能是好的取决于复杂性.

到目前为止我所知道的是,要解决上述方法,唯一可行的方法是实现访问者模式,除了使用访问者模式之外,还有其他方法可以解决上述设计吗?

我可以从访问者模式看到的一个问题是访问者模式的accept方法没有返回值,如果accept()方法不能完全满足需求,这有时候不方便.

java design-patterns liskov-substitution-principle instanceof visitor-pattern

5
推荐指数
1
解决办法
671
查看次数

代码约定和继承(重写方法的前提条件)

目前代码契约不允许派生类中成员的前提条件,其中成员已经在基类中设置了前提条件(我实际上当前得到警告而不是错误).我不明白这背后的逻辑.我理解它与Liskov的替换规则有关,声明派生类应始终能够在父预期的地方使用.当然"使用"意味着按预期工作.对于接口而言,这对我来说似乎没问题,因为实现接口的不同类型不会添加状态,因此可以完全强制合同.但是,当您从基类继承时,您正在这样做以添加状态和特殊功能,并且通常情况下,覆盖方法会有额外的要求.为什么不能像前置条件和对象不变量一样将前置条件与AND组合在一起?

看看下面:

class Speaker
{
    public bool IsPlugged { get; set; }
    protected virtual void Beep()
    {
        Contract.Requires(IsPlugged);
        Console.WriteLine("Beep");
    }
}

class WirelessSpeaker : Speaker
{
    public bool TransmitterIsOn { get; set; }
    protected override void Beep()
    {
        Contract.Requires(TransmitterIsOn);
        base.Beep();
    }
}
Run Code Online (Sandbox Code Playgroud)

你可能会争辩说这个类层次结构打破了Liskov的规则,因为当传递给期望a的方法时,无线扬声器可能无法发出蜂鸣声Speaker.但这不是我们使用代码合同的原因吗?确保满足要求?

.net c# liskov-substitution-principle code-contracts solid-principles

5
推荐指数
1
解决办法
753
查看次数

Java 数组协方差是否违反 Liskov 替换原则?

我正在阅读为什么 Java 中的数组协变很糟糕(为什么数组协变而泛型是不变的?)。如果 aDog是 的子类型Animal,则 aDog[]是 的子类型Animal[]。这是一个问题,因为可以这样做:

Animal[] animals = new Dog[1];
animals[0] = new Cat();
Run Code Online (Sandbox Code Playgroud)

这与“正确”实现的泛型不同。AList<Dog>不是的子类型List<Animal>

我试图理解为什么它不好的本质,并且刚刚阅读了 LSP。它是否以任何方式违反了 LSP?似乎没有明显的违规行为。

generics language-design liskov-substitution-principle covariance solid-principles

5
推荐指数
1
解决办法
503
查看次数

如何在 PHP 中的子类继承方法中定义更严格的类型?

假设我有这样的三门课。

abstract class A {
   abstract protected function doSomething($object): array;
}

class B extends A {
   protected function doSomething(SomeObject $object): array
   {
       // something
   }
}

class C extends A {
   protected function doSomething(OtherObject $object): array
   {
       // something
   }
}
Run Code Online (Sandbox Code Playgroud)

根据 PHP 的继承原理,上述结构不是合法的 PHP 代码,因为方法定义与基类不兼容。我当然可以做类似的事情

class B extends A {
    protected function doSomething($object): array
    {
        if (!is_a($object, 'SomeObject')) {
            throw new Exception('Object passed to method is not of the correct class for this method.');
        }

        // something
    }
} …
Run Code Online (Sandbox Code Playgroud)

php oop liskov-substitution-principle solid-principles

5
推荐指数
1
解决办法
1354
查看次数