Code to the Interface Principle keeps client code dependent on a superclass interface rather than a specific subclass. At runtime, polymorphism lets the same code work with any compatible implementation. section 2.3.3 section 2.4
Apply the principle by:
- Storing objects through a shared superclass or interface, such as Attributes, instead of naming FictionAttrs or CookbookAttrs in shared state. section 2.3.3
- Calling the shared operation, such as is_match(), and allowing the assigned subclass to provide specialized behavior. section 2.3.3
- Keep client code flexible as new compatible subclasses are added, while avoiding unnecessary subclass proliferation and hardcoded behavior. section 2.4
Books and interchangeable strategies
A Book stores an Attributes object, which may actually be FictionAttrs or CookbookAttrs. Catalogue searches Book objects and delegates matching to book.attributes.is_match(target_attrs). The same design appears in Strategy: Sport stores PlayerStrategy and VenueStrategy interfaces, so Baseball, Football, and Volleyball can receive interchangeable algorithms at runtime. section 2.3.3 section 8.2.3
Listing 2.12 (Program 2.3 Books-3): catalogue.py
from fiction import Fiction
from fictionattrs import FictionAttrs
from cookbook import Cookbook
class Catalogue:
def __init__(self):
self._booklist = []
def add(self, attrs): #1
if isinstance(attrs, FictionAttrs): book = Fiction(attrs)
else: book = Cookbook(attrs)
self._booklist.append(book)
def find_fiction(self, target_attrs): #2
return [book for book in self._booklist
if ( isinstance(book, Fiction) #3
and book.attributes.is_match(target_attrs))
]
def find_cookbook(self, target_attrs): #4
return [book for book in self._booklist
if ( isinstance(book, Cookbook) #5
and book.attributes.is_match(target_attrs))
]
Inspect the Catalogue implementation to see shared Book storage, subclass selection, and delegated interface calls. section 2.3.3
Listing 8.12 (Program 8.4 Sports-StrategyDP): sport.py
class Sport:
_SPORT_TYPE = ''
def __init__(self, player_strategy, venue_strategy):
self._player_strategy = player_strategy #1
self._venue_strategy = venue_strategy #1
@property
def SPORT_TYPE(self): return self._SPORT_TYPE
@property
def player_strategy(self): return self._player_strategy #2
@property
def venue_strategy(self): return self._venue_strategy #2
@player_strategy.setter
def player_strategy(self, ps): #3
self._player_strategy = ps
@venue_strategy.setter
def venue_strategy(self, vs): #3
self._venue_strategy = vs
def recruit_players(self):
return self._player_strategy.strategy()
def reserve_venue(self):
return self._venue_strategy.strategy()
Inspect Sport to see interface-typed strategy references, delegation, and runtime replacement of algorithms. section 8.2.3

