liveBook · Manning

Coupling

As explained in Software Design for Python Programmers

Loose coupling is a relationship between software components in which each has few dependencies on the implementation of the others.

Loose coupling is a relationship between software components in which each has few dependencies on the implementation details of the others. Minimizing these dependencies makes change less likely to spread through the system. section 4.2.2

A class becomes dependent when it references another class. Prefer passing objects as arguments, aggregating collaborators directly, or creating them locally; avoid reaching through one object to call methods on another object returned by it. section 5.6

Encapsulate changing book attributes

A catalogue initially knows individual book attributes for adding and searching books. Adding publication year and genre then forces changes in both Catalogue methods. Encapsulate those varying attributes and their is_match() behavior in Attributes. Catalogue passes Attributes objects and delegates matching, so later attribute changes remain localized. section 2.3.2

Design choices that reduce implementation knowledge include:

  • Make collaborators depend on stable operations rather than their storage or internal representation. section 4.2.2
  • Replace collection-specific reporting logic with a common iteration abstraction when a report must support lists, generators, and dictionaries. section 11.1.2
  • Register interchangeable subscribers instead of hardcoding each subscriber’s method name and implementation. section 12.1.2
  • Represent state-specific behavior in State subclasses and let the current state handle actions and return the next state. section 13.1.3
  • Choose composition with Strategy when complete algorithms must be interchangeable; choose inheritance with Template Method when a superclass owns the algorithm outline. section 8.3
Listing 2.4 (Program 2.2 Books-2): attributes.py
from enum import Enum

class Genre(Enum):    #1
    UNSPECIFIED = 0
    ADVENTURE   = 1
    CLASSICS    = 2
    DETECTIVE   = 3
    FANTASY     = 4
    HISTORIC    = 5
    HORROR      = 6
    ROMANCE     = 7
    SCIFI       = 8

    def __str__(self): return self.name.lower()

class Attributes:

    @staticmethod
    def _equal_ignore_case(target_str, other_str):    #2
        if len(target_str) == 0: 
            return True
        else:
            return target_str.casefold() == other_str.casefold()

    def __init__(self, title, last, first, year, genre):
        self._title = title
        self._last  = last
        self._first = first
        self._year  = year     #3
        self._genre = genre     #3

    @property
    def title(self): return self._title

    @property
    def last(self): return self._last

    @property
    def first(self): return self._first

    @property
    def year(self):  return self._year

    @property
    def genre(self): return self._genre

    def is_match(self, target_attrs):    #4
        return (     
                Attributes._equal_ignore_case(target_attrs.title, 
                                              self._title)
            and Attributes._equal_ignore_case(target_attrs.last,  
                                              self._last)
            and Attributes._equal_ignore_case(target_attrs.first, 
                                              self._first)
            and (    (target_attrs.year  == 0)
                  or (target_attrs.year  == self._year))
            and (    (target_attrs.genre == Genre.UNSPECIFIED)
                  or (target_attrs.genre == self._genre))
        )

    def __str__(self):
        return (f"{{TITLE: '{self._title}', LAST: '{self._last}', "
                f"FIRST: '{self._first}', YEAR: {self._year}, "    #5
                f"GENRE: {self._genre}}}")     #5

Inspect the Attributes class that encapsulates book fields, case-insensitive matching, and genre enumeration. section 2.3.2

Figure 13.3 The subclasses of superclass State encapsulate handling the customer and machine actions for each state of the ticket machine. Each action method of the subclasses returns a State object that is the next state for the ticket machine to transition to. By aggregating the State subclasses in class StatesBlock, the subclasses are loosely coupled with each other and with class TicketMachine. Each action method of class TicketMachine defers to the corresponding method of the current State object pointed to by its private _state instance variable.
A screenshot of a computer

AI-generated content may be incorrect.

Trace how State subclasses isolate ticket-machine behavior and how StatesBlock connects them without making TicketMachine manage every transition. section 13.1.3

How Software Design for Python Programmers covers it

How deep it goes
Explains dependencies, least knowledge, delegation, and refactoring examples, while deferring formal measurement of coupling.
Examples
Demonstrates book catalogues, team reports, baseball subscribers, ticket-machine states, and interchangeable algorithms.
What it assumes
Assumes basic classes, objects, references, parameters, inheritance, and composition while introducing dependency rules through examples.
What you can do after
Apply it via encapsulation, delegation, Iterator, Observer, State, Strategy, and Template Method refactorings.
How it connects
Connects loose coupling to encapsulation, delegation, the Principle of Least Knowledge, the Law of Demeter, and design patterns.

Also explained in

Compare how 17 books explain coupling →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Software Design for Python Programmers. The section links point to the parts of the book it draws on.