Raja
Raja

Reputation: 89

Need clarity in Understanding liskov substitution principle

LSP definition states that,If S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program.

  1. Preconditions cannot be strengthened in a subtype
  2. Postconditions cannot be weakened in a subtype.
  3. Invariants of the supertype must be preserved in a subtype.

For example, I have below classes Is this a violation of( Preconditions cannot be strengthened in a subtype). I am trying to wrap my head around this ,Can someone please provide a good example to understand it.

Class Switch:
   def __init__(self,ip,dc):
       self.ip=ip
       self.dc=dc

class CiscoSwitch(Switch):
   def __init__(self,ip,dc,zone):
       super().__init__(ip,dc)
       self.zone=zone

class JuniperSwitch(Switch):
   def __init__(self,ip,dc,zone):
       super().__init__(ip,dc)
       self.zone=zone

Upvotes: 1

Views: 1274

Answers (1)

LSP principle works through interfaces, that is, what is public in the object/value. In the case of Python, you have attributes and methods that are public and therefore, if you are implementing an interface you must adhere to it. In your example, the Switch class defines an interface only regarding its attributes, that is, it has the ip and dc fields. Since you are calling super in CiscoSwitch and JuniperSwitch, they both have those fields, and therefore implement the "interface" of Switch and they may replace it.

Now, let's tackle the conditions you mentioned:

  1. Preconditions cannot be strengthened in a subtype

Suppose you have an interface with a method that colors a shape and this method accepts only hexadecimal colors ("#123456") or rgb colors ((123,124,125)). Suppose you create a class Rectangle that implements this interface, but it accepts only rgb colors. You're strengthening the pre-condition. If you have this line in your code: generic_shape.color("#123456")

You cannot replace your Rectangle in it, so you are breaking LSP.

  1. Postconditions cannot be weakened in the subtype

A classical example would be returning None for a method that should not return None. Suppose that in the Shape interface, you have a getSide method, and you create a Circle class, and when implementing this method, you return None. This breaks the caller expectative and may cause an unexpected error:

side = generic_shape.get_side() # suppose it is a circle
scaled_side = side * 2 # you get an error
  1. Invariants of the supertype must be preserved in a subtype

This one is more complex in my opinion, because it is hard to make it explicit. The only example I can think is keeping a property non-Null, suppose in your example you have a Switch that doesn't use IP (maybe uses MAC-addr), if the Switch interface expects that the ip field should not be None, your MAC-Switch will be broking this interface.

I hope it helps!

Upvotes: 2

Related Questions