如何避免破坏Liskov替换原则(LSP)? [英] How can I avoid breaking Liskov Substitution Principle (LSP)?

查看:186
本文介绍了如何避免破坏Liskov替换原则(LSP)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的情况与Code Complete中提到的 Steve McConnell 非常相似。只有我的问题是基于车辆和三轮车才恰好依据法律属于汽车类别。到目前为止,汽车有四个轮子。任何方式我的域都是不必要的复杂,所以很容易坚持下面的猫示例。

I am in a situation very similar to what Steve McConnell's in Code Complete has mentioned . Only that my problem is based of Vehicles and Trike happens to be on that by law falls in the category of Cars . Cars had four wheels until now . Any way my domain is unnecessarily complex so it is easy to stick with cats example below.


要怀疑覆盖例程的类并且做
里面没有任何内容派生例程这通常表示基类的
设计中的错误。例如,假设您有一个类Cat和一个
例程Scratch()并假设您最终发现一些
猫被声明并且无法划伤。您可能想要创建一个派生自Cat命名为ScratchlessCat的
类,并覆盖Scratch()
例程以不执行任何操作。这种方法存在一些问题:

Be suspicious of classes that override a routine and do nothing inside the derived routine This typically indicates an error in the design of the base class. For instance, suppose you have a class Cat and a routine Scratch() and suppose that you eventually find out that some cats are declawed and can't scratch. You might be tempted to create a class derived from Cat named ScratchlessCat and override the Scratch() routine to do nothing. This approach presents several problems:

它违反了Cat
类中的抽象(接口契约),通过改变其接口的语义。

It violates the abstraction (interface contract) presented in the Cat class by changing the semantics of its interface.

当您将其扩展到其他
派生类时,此方法很快就会失控。当你发现没有尾巴的猫时会发生什么?还是一只不能捕捉老鼠的
猫?还是一只不喝牛奶的猫?
最终你会得到像
ScratchlessTaillessMicelessMilklessCat这样的派生类。

This approach quickly gets out of control when you extend it to other derived classes. What happens when you find a cat without a tail? Or a cat that doesn't catch mice? Or a cat that doesn't drink milk? Eventually you'll end up with derived classes like ScratchlessTaillessMicelessMilklessCat.

随着时间的推移,这种方法会导致代码混淆为
维护,因为祖先类
的接口和行为对其后代的行为意味着很少或根本没有。

Over time, this approach gives rise to code that's confusing to maintain because the interfaces and behavior of the ancestor classes imply little or nothing about the behavior of their descendants.

解决此问题的地方不在基类,但在
原始Cat类中。创建一个Claws类,并在
Cats类中包含它。根本问题是假设所有的猫都抓了,
所以在源头解决这个问题,而不是仅仅在目的地的
处包扎它。

The place to fix this problem is not in the base class, but in the original Cat class. Create a Claws class and contain that within the Cats class. The root problem was the assumption that all cats scratch, so fix that problem at the source, rather than just bandaging it at the destination.

根据他上面的伟大着作中的文字。以下是不好的

According to the text from his great book above . Following is bad

父类不必是抽象的

public abstract class Cat {
   public void scratch() {
      System.out.println("I can scratch");
   }
}

派生类

public class ScratchlessCat extends Cat {
   @Override
   public void scratch() {
      // do nothing
   }
}

现在他建议创建另一个类 Claws ,但我不明白如何使用这个类来避免需要 ScratchlessCat #Scratch

Now he suggests creating another class Claws, but I do not understand how can I use this class to avoid the need for ScratchlessCat#Scratch.

推荐答案

你仍然会有一个 scratch()方法,但它不会被覆盖派生类:

You would still have a scratch() method, but it will not be overridden by the derived classes:

public class Cat {
  Claw claw_;
  public Cat(Claw claw) {claw = claw_;}
  public final void scratch() {
    if (claw_ != null) {
      claw_.scratch(this);
    }
  }
}

这允许您委派将逻辑划分到包含的 Claw 对象(如果存在)(如果没有爪子则不刮擦)。从cat派生的类在如何划分的问题上没有发言权,因此不需要根据能力创建阴影层次结构。

This allows you to delegate the scratching logic to the contained Claw object, if present (and not scratch if there are no claws). Classes derived from cat have no say in the matter on how to scratch, so no need to create shadow hierarchies based on abilities.

另外,因为派生类不能改变方法实现,它们没有打破基类接口中 scratch()方法的预期语义的问题。

Also, because the derived classes cannot change the method implementation, there is no problem of them breaking the intended semantics of the scratch() method in the base class's interface.

如果你把它带到极端,你可能会发现你有很多类而且没有很多派生 - 大多数逻辑被委托给组合对象,而不是委托给派生类。

If you take this to the extremes, you might find that you have a lot of classes and not many derivations -- most logic is delegated to the composition objects, not entrusted to the derived classes.

这篇关于如何避免破坏Liskov替换原则(LSP)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆