How can I avoid breaking Liskov Substitution Principle (LSP)?

前端 未结 2 1090
星月不相逢
星月不相逢 2020-12-28 18:51

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

相关标签:
2条回答
  • 2020-12-28 19:20

    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);
        }
      }
    }
    

    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.

    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.

    0 讨论(0)
  • 2020-12-28 19:25

    That not all cats have claws and are capable of scratching is a big clue that Cat should not define a public scratch method in its API. The first step is to consider why you defined scratch in the first place. Perhaps cats scratch if they can when attacked; if not they hiss or run away.

    public class Cat extends Animal {
        private Claws claws;
    
        public void onAttacked(Animal attacker) {
            if (claws != null) {
                claws.scratch(attacker);
            }
            else {
                // Assumes all cats can hiss.
                // This may also be untrue and you need Voicebox.
                // Rinse and repeat.
                hiss();
            }
        }
    }
    

    Now you can substitute any Cat subclass for another and it will behave correctly depending on whether or not it has claws. You could define a DefenseMechanism class to organize the various defenses such as Scratch, Hiss, Bite, etc.

    0 讨论(0)
提交回复
热议问题