Принципы и практики разработки ПО 2 / Principles and practices of software development 2

Alexander Granin
Alexander GraninSoftware Developer, Independent Consultant at Independent Consultant
Принципы и практики
разработки ПО
Лекция 2
SOLID principles
S SRP
O OCP
L LSP
I ISP
D DIP
Single Responsibility Principle
Open-Close Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
class ILampSwitcher:
def switch(self, on_off):
pass
def is_on(self):
return self.light_on
class DaylightLamp(ILampSwitcher):
pass
class TableLamp(ILampSwitcher):
pass
Liskov Substitution Principle (LSP)
ILampSwitcher
TableLampDaylightLamp
+switch(on_off: bool)
+is_on(): bool
def turn_all_on(lamps):
for lamp in lamps:
lamp.switch(True)
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
Liskov Substitution Principle (LSP)
TableLampDaylightLamp
ILampSwitcher
+switch(on_off: bool)
+is_on(): bool
def turn_all_on(lamps):
for lamp in lamps:
lamp.switch(True)
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
turn_all_on([l1, l2]) # OK
turn_all_on([l3, l4]) # Exception
Liskov Substitution Principle (LSP)
TableLampDaylightLamp
ILampSwitcher
+switch(on_off: bool)
+is_on(): bool
def turn_all_on(lamps):
for lamp in lamps:
lamp.switch(True)
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
turn_all_on([l1, l2]) # OK
turn_all_on([l3, l4]) # Exception
Liskov Substitution Principle (LSP)
class DaylightLamp(ILampSwitcher):
def switch(self, on_off):
self.light_on = on_off
def turn_all_on(lamps):
for lamp in lamps:
lamp.switch(True)
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
turn_all_on([l1, l2]) # OK
turn_all_on([l3, l4]) # Exception
Liskov Substitution Principle (LSP)
class DaylightLamp(ILampSwitcher):
def switch(self, on_off):
self.light_on = on_off
class TableLamp(ILampSwitcher):
def switch(self, on_off):
# debug
f = open("c:v_pupkintmp.txt", 'w')
f.write("Lamp state: " + str(self.is_on()))
self.light_on = on_off
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
turn_all_on([l1, l2]) # OK
turn_all_on([l1, l2]) # OK
turn_all_on([l3, l4]) # OK
turn_all_on([l3, l4]) # Exception
Liskov Substitution Principle (LSP)
class DaylightLamp(ILampSwitcher):
def switch(self, on_off):
...
class TableLamp(ILampSwitcher):
def switch(self, on_off):
...
l1 = DaylightLamp()
l2 = DaylightLamp()
l3 = TableLamp()
l4 = TableLamp()
turn_all_on([l1, l2]) # OK
turn_all_on([l1, l2]) # OK
turn_all_on([l3, l4]) # OK
turn_all_on([l3, l4]) # Exception
Liskov Substitution Principle (LSP)
class DaylightLamp(ILampSwitcher):
def switch(self, on_off):
self.light_on = on_off
class TableLamp(ILampSwitcher):
def switch(self, on_off):
if self.light_on and on_off:
raise Exception("Already on.")
if not self.light_on and not on_off:
raise Exception("Already off.")
self.light_on = on_off
class ILampSwitcher:
# Switches on or off.
# No throw of exceptions.
def switch(self, on_off):
pass
# Returns is lamp on.
# No throw of exceptions.
def is_on(self):
return self.light_on
# Blinks every interval (ms) if turned on.
# Throws NotSupportedException if lamp can't do this.
def blink(interval):
pass
Keeping contracts == obey LSP
class DaylightLamp(ILampSwitcher):
def switch(self, on_off):
self.light_on = on_off
def blink(interval):
raise NotSupportedException()
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switch_all(self, on_off: bool):
pass
Contracts, interface consistency and LSP
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switch_all(self, on_off: bool):
pass
class MultiLamp(IMultiLampSwitcher):
def __init__(self, lamps_count):
self.lamps_count = lamps_count
self.lamps = [False] * lamps_count
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
self.lamps[idx] = on_off
Contracts, interface consistency and LSP
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switch_all(self, on_off: bool):
pass
class MultiLamp(IMultiLampSwitcher):
def __init__(self, lamps_count):
self.lamps_count = lamps_count
self.lamps = [False] * lamps_count
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
self.lamps[idx] = on_off
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def __init__(self):
super(SmartOfficeLamp, self).__init__(3)
self.switching_times = [0] * 3
def switch(self, idx, on_off: bool):
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
super(SmartOfficeLamp, self).switch_all(on_off)
Contracts, interface consistency and LSP
IMultiLampSwitcher
MultiLamp
+switch(idx:int, on_off: bool)
+switch_all(on_off:bool)
SmartOfficeLamp
+switch(idx:int, on_off: bool)
+switch_all(on_off:bool)
+switch(idx:int, on_off: bool)
+switch_all(on_off:bool)
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
self.lamps[idx] = on_off
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
super(SmartOfficeLamp, self).switch_all(on_off)
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
self.lamps[idx] = on_off
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch_all(on_off)
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
self.lamps[idx] = on_off
l = SmartOfficeLamp()
print(l.lamps) # [False, False, False]
print(l.switching_times) # [0, 0, 0]
l.switch_all(True)
print(l.lamps) # [True, True, True]
print(l.switching_times) # [1, 1, 1]
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch_all(on_off)
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
# self.lamps[idx] = on_off
self.switch(idx, on_off)
l = SmartOfficeLamp()
print(l.lamps) # [False, False, False]
print(l.switching_times) # [0, 0, 0]
l.switch_all(True)
print(l.lamps)
print(l.switching_times)
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch_all(on_off)
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
# self.lamps[idx] = on_off
self.switch(idx, on_off)
l = SmartOfficeLamp()
print(l.lamps) # [False, False, False]
print(l.switching_times) # [0, 0, 0]
l.switch_all(True)
print(l.lamps) # [True, True, True]
print(l.switching_times) # [2, 2, 2]
Contracts, interface consistency and LSP
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch(idx, on_off)
def switch_all(self, on_off: bool):
for idx in range(self.lamps_count):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch_all(on_off)
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switchers_count(self):
pass
@staticmethod
def switch_all(multi_lamp_switcher, on_off):
cnt = multi_lamp_switcher.switchers_count()
for idx in range(cnt):
multi_lamp_switcher.switch(idx, on_off)
Contracts, interface consistency and LSP
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switchers_count(self):
pass
@staticmethod
def switch_all(multi_lamp_switcher, on_off):
cnt = multi_lamp_switcher.switchers_count()
for idx in range(cnt):
multi_lamp_switcher.switch(idx, on_off)
Contracts, interface consistency and LSP
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switchers_count(self):
return self.lamps_count
class IMultiLampSwitcher:
def switch(self, idx, on_off: bool):
pass
def switchers_count(self):
pass
@staticmethod
def switch_all(multi_lamp_switcher, on_off):
cnt = multi_lamp_switcher.switchers_count()
for idx in range(cnt):
multi_lamp_switcher.switch(idx, on_off)
Contracts, interface consistency and LSP
class MultiLamp(IMultiLampSwitcher):
def switch(self, idx, on_off: bool):
self.lamps[idx] = on_off
def switchers_count(self):
return self.lamps_count
class SmartOfficeLamp(MultiLamp):
def switch(self, idx, on_off: bool):
if on_off != self.lamps[idx]:
self.switching_times[idx] += 1
super(SmartOfficeLamp, self).switch(idx, on_off)
l = SmartOfficeLamp()
IMultiLampSwitcher.switch_all(l, True)
The end
1 of 23

More Related Content

Similar to Принципы и практики разработки ПО 2 / Principles and practices of software development 2

PLSQL NotePLSQL Note
PLSQL NoteArun Sial
246 views16 slides

Similar to Принципы и практики разработки ПО 2 / Principles and practices of software development 2(20)

Unidad 4 robotica.docxUnidad 4 robotica.docx
Unidad 4 robotica.docx
luisgabielnavarro15 views
PLSQL NotePLSQL Note
PLSQL Note
Arun Sial246 views
An Introduction to the SOLID PrinciplesAn Introduction to the SOLID Principles
An Introduction to the SOLID Principles
Attila Bertók108 views
ArduinoArduino
Arduino
josnihmurni290725 views
Java tutorial  PPTJava tutorial  PPT
Java tutorial PPT
Intelligo Technologies6.6K views
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
Intelligo Technologies177.3K views
Zope component architechtureZope component architechture
Zope component architechture
Anatoly Bubenkov2.4K views
Introduction to JavaIntroduction to Java
Introduction to Java
Ashita Agrawal1.1K views
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
Charles Nutter2.1K views
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
Jens-Christian Fischer18.6K views
Pl sql programmePl sql programme
Pl sql programme
Dhilip Prakash106 views
Pl sql programmePl sql programme
Pl sql programme
Dhilip Prakash386 views

More from Alexander Granin(20)

Final tagless vs free monadFinal tagless vs free monad
Final tagless vs free monad
Alexander Granin158 views
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
Alexander Granin579 views
Закон Деметры / Demetra's lawЗакон Деметры / Demetra's law
Закон Деметры / Demetra's law
Alexander Granin149 views
Design of big applications in FPDesign of big applications in FP
Design of big applications in FP
Alexander Granin129 views
Functional programming in C++ LambdaNskFunctional programming in C++ LambdaNsk
Functional programming in C++ LambdaNsk
Alexander Granin464 views
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++
Alexander Granin1.7K views

Recently uploaded(20)

Принципы и практики разработки ПО 2 / Principles and practices of software development 2

  • 2. SOLID principles S SRP O OCP L LSP I ISP D DIP Single Responsibility Principle Open-Close Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle
  • 3. class ILampSwitcher: def switch(self, on_off): pass def is_on(self): return self.light_on class DaylightLamp(ILampSwitcher): pass class TableLamp(ILampSwitcher): pass Liskov Substitution Principle (LSP) ILampSwitcher TableLampDaylightLamp +switch(on_off: bool) +is_on(): bool
  • 4. def turn_all_on(lamps): for lamp in lamps: lamp.switch(True) l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() Liskov Substitution Principle (LSP) TableLampDaylightLamp ILampSwitcher +switch(on_off: bool) +is_on(): bool
  • 5. def turn_all_on(lamps): for lamp in lamps: lamp.switch(True) l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() turn_all_on([l1, l2]) # OK turn_all_on([l3, l4]) # Exception Liskov Substitution Principle (LSP) TableLampDaylightLamp ILampSwitcher +switch(on_off: bool) +is_on(): bool
  • 6. def turn_all_on(lamps): for lamp in lamps: lamp.switch(True) l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() turn_all_on([l1, l2]) # OK turn_all_on([l3, l4]) # Exception Liskov Substitution Principle (LSP) class DaylightLamp(ILampSwitcher): def switch(self, on_off): self.light_on = on_off
  • 7. def turn_all_on(lamps): for lamp in lamps: lamp.switch(True) l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() turn_all_on([l1, l2]) # OK turn_all_on([l3, l4]) # Exception Liskov Substitution Principle (LSP) class DaylightLamp(ILampSwitcher): def switch(self, on_off): self.light_on = on_off class TableLamp(ILampSwitcher): def switch(self, on_off): # debug f = open("c:v_pupkintmp.txt", 'w') f.write("Lamp state: " + str(self.is_on())) self.light_on = on_off
  • 8. l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() turn_all_on([l1, l2]) # OK turn_all_on([l1, l2]) # OK turn_all_on([l3, l4]) # OK turn_all_on([l3, l4]) # Exception Liskov Substitution Principle (LSP) class DaylightLamp(ILampSwitcher): def switch(self, on_off): ... class TableLamp(ILampSwitcher): def switch(self, on_off): ...
  • 9. l1 = DaylightLamp() l2 = DaylightLamp() l3 = TableLamp() l4 = TableLamp() turn_all_on([l1, l2]) # OK turn_all_on([l1, l2]) # OK turn_all_on([l3, l4]) # OK turn_all_on([l3, l4]) # Exception Liskov Substitution Principle (LSP) class DaylightLamp(ILampSwitcher): def switch(self, on_off): self.light_on = on_off class TableLamp(ILampSwitcher): def switch(self, on_off): if self.light_on and on_off: raise Exception("Already on.") if not self.light_on and not on_off: raise Exception("Already off.") self.light_on = on_off
  • 10. class ILampSwitcher: # Switches on or off. # No throw of exceptions. def switch(self, on_off): pass # Returns is lamp on. # No throw of exceptions. def is_on(self): return self.light_on # Blinks every interval (ms) if turned on. # Throws NotSupportedException if lamp can't do this. def blink(interval): pass Keeping contracts == obey LSP class DaylightLamp(ILampSwitcher): def switch(self, on_off): self.light_on = on_off def blink(interval): raise NotSupportedException()
  • 11. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switch_all(self, on_off: bool): pass Contracts, interface consistency and LSP
  • 12. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switch_all(self, on_off: bool): pass class MultiLamp(IMultiLampSwitcher): def __init__(self, lamps_count): self.lamps_count = lamps_count self.lamps = [False] * lamps_count def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): self.lamps[idx] = on_off Contracts, interface consistency and LSP
  • 13. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switch_all(self, on_off: bool): pass class MultiLamp(IMultiLampSwitcher): def __init__(self, lamps_count): self.lamps_count = lamps_count self.lamps = [False] * lamps_count def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): self.lamps[idx] = on_off Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def __init__(self): super(SmartOfficeLamp, self).__init__(3) self.switching_times = [0] * 3 def switch(self, idx, on_off: bool): super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): super(SmartOfficeLamp, self).switch_all(on_off)
  • 14. Contracts, interface consistency and LSP IMultiLampSwitcher MultiLamp +switch(idx:int, on_off: bool) +switch_all(on_off:bool) SmartOfficeLamp +switch(idx:int, on_off: bool) +switch_all(on_off:bool) +switch(idx:int, on_off: bool) +switch_all(on_off:bool)
  • 15. class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): self.lamps[idx] = on_off Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): super(SmartOfficeLamp, self).switch_all(on_off)
  • 16. class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): self.lamps[idx] = on_off Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): for idx in range(self.lamps_count): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch_all(on_off)
  • 17. class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): self.lamps[idx] = on_off l = SmartOfficeLamp() print(l.lamps) # [False, False, False] print(l.switching_times) # [0, 0, 0] l.switch_all(True) print(l.lamps) # [True, True, True] print(l.switching_times) # [1, 1, 1] Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): for idx in range(self.lamps_count): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch_all(on_off)
  • 18. class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): # self.lamps[idx] = on_off self.switch(idx, on_off) l = SmartOfficeLamp() print(l.lamps) # [False, False, False] print(l.switching_times) # [0, 0, 0] l.switch_all(True) print(l.lamps) print(l.switching_times) Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): for idx in range(self.lamps_count): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch_all(on_off)
  • 19. class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switch_all(self, on_off: bool): for idx in range(self.lamps_count): # self.lamps[idx] = on_off self.switch(idx, on_off) l = SmartOfficeLamp() print(l.lamps) # [False, False, False] print(l.switching_times) # [0, 0, 0] l.switch_all(True) print(l.lamps) # [True, True, True] print(l.switching_times) # [2, 2, 2] Contracts, interface consistency and LSP class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch(idx, on_off) def switch_all(self, on_off: bool): for idx in range(self.lamps_count): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch_all(on_off)
  • 20. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switchers_count(self): pass @staticmethod def switch_all(multi_lamp_switcher, on_off): cnt = multi_lamp_switcher.switchers_count() for idx in range(cnt): multi_lamp_switcher.switch(idx, on_off) Contracts, interface consistency and LSP
  • 21. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switchers_count(self): pass @staticmethod def switch_all(multi_lamp_switcher, on_off): cnt = multi_lamp_switcher.switchers_count() for idx in range(cnt): multi_lamp_switcher.switch(idx, on_off) Contracts, interface consistency and LSP class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switchers_count(self): return self.lamps_count
  • 22. class IMultiLampSwitcher: def switch(self, idx, on_off: bool): pass def switchers_count(self): pass @staticmethod def switch_all(multi_lamp_switcher, on_off): cnt = multi_lamp_switcher.switchers_count() for idx in range(cnt): multi_lamp_switcher.switch(idx, on_off) Contracts, interface consistency and LSP class MultiLamp(IMultiLampSwitcher): def switch(self, idx, on_off: bool): self.lamps[idx] = on_off def switchers_count(self): return self.lamps_count class SmartOfficeLamp(MultiLamp): def switch(self, idx, on_off: bool): if on_off != self.lamps[idx]: self.switching_times[idx] += 1 super(SmartOfficeLamp, self).switch(idx, on_off) l = SmartOfficeLamp() IMultiLampSwitcher.switch_all(l, True)