# The Composition Over Inheritance Principle¶ ![rw-book-cover](https://readwise-assets.s3.amazonaws.com/static/images/article1.be68295a7e40.png) ## Metadata - Author: [[python-patterns.guide]] - Full Title: The Composition Over Inheritance Principle¶ - Category: #articles - URL: https://python-patterns.guide/gang-of-four/composition-over-inheritance/ - Archive: https://web-archive.alecodes.page/bookmarks?bf=1&search=&title=The%20Composition%20Over%20Inheritance%20Principle%C2%B6 > [!tldr] > The Composition Over Inheritance principle emphasizes that using composition (combining classes) is often more effective than inheritance (subclassing) for managing complexity in code. By employing design patterns like Adapter, Bridge, and Decorator, developers can create flexible logging systems that separate filtering from logging behavior. This approach allows for easier maintenance and the ability to mix and match different filters and handlers at runtime without creating a large number of subclasses. ## Highlights Favor object composition over class inheritance. [View Highlight](https://read.readwise.io/read/01j8bahv00beg9tchtr4b8hkem)) A crucial weakness of inheritance as a design strategy is that a class often needs to be specialized along several different design axes at once, leading to what the Gang of Four call “a proliferation of classes” in their Bridge chapter and “an explosion of subclasses to support every combination” in their Decorator chapter. [View Highlight](https://read.readwise.io/read/01j8bakccctxe895jka6vmvdyw)) The total number of classes will increase geometrically if *m* and *n* both continue to grow. This is the “proliferation of classes” and “explosion of subclasses” that the Gang of Four want to avoid. [View Highlight](https://read.readwise.io/read/01j8baqph5c3v99rgn0p32tj70)) The solution is to recognize that a class responsible for both filtering messages and logging messages is too complicated. In modern Object Oriented practice, it would be accused of violating the “Single Responsibility Principle.” [View Highlight](https://read.readwise.io/read/01j8bar8r89tdkkqwg09cy61bk)) One solution is the Adapter Pattern: to decide that the original logger class doesn’t need to be improved, because any mechanism for outputting messages can be wrapped up to look like the file object that the logger is expecting. [View Highlight](https://read.readwise.io/read/01j8bat4m4e3sttcc3x9x8nbtw)) Python encourages duck typing [View Highlight](https://read.readwise.io/read/01j8bav8whbf9z87ssg40m23kz)) > [!note] > Duck typing: A programming concept primarily associated with the Python language, duck typing emphasizes an object's behavior (methods and properties) over its explicit type. The term is derived from the saying, "If it looks like a duck and quacks like a duck, it must be a duck," indicating that the suitability of an object is determined by the presence of certain methods and attributes rather than its inheritance or class. This approach allows for greater flexibility and adaptability in coding, as it encourages developers to focus on what an object can do rather than what it is, facilitating the creation of lightweight adapters and promoting code reuse. And so the subclass explosion is avoided! Logger objects and adapter objects can be freely mixed and matched at runtime without the need to create any further classes: [View Highlight](https://read.readwise.io/read/01j8baynydfgxctvwbdw0rca62)) The Bridge Pattern splits a class’s behavior between an outer “abstraction” object that the caller sees and an “implementation” object that’s wrapped inside. We can apply the Bridge Pattern to our logging example if we make the (perhaps slightly arbitrary) decision that filtering belongs out in the “abstraction” class while output belongs in the “implementation” class. [View Highlight](https://read.readwise.io/read/01j8bb0dxxf1dewfg0jyv6w8tn)) --- New highlights added at 2024-10-13 4:11 PM Instead of file output being native to the `Logger` but non-file output requiring an additional class, a functioning logger is now always built by composing an abstraction with an implementation. [View Highlight](https://read.readwise.io/read/01j8mcakzs1dpqmst4sgsxby1k)) The reason we cannot stack two filters is that there’s an asymmetry between the interface they offer and the interface they wrap: they offer a `log()` method but call their handler’s `emit()` method. Wrapping one filter in another would result in an `AttributeError` when the outer filter tried to call the inner filter’s `emit()`. If we instead pivot our filters and handlers to offering the same interface, so that they all alike offer a `log()` method, then we have arrived at the Decorator Pattern [View Highlight](https://read.readwise.io/read/01j8r6kf6c1dp9y5sbaxss465r)) Python logging module implements its own Composition Over Inheritance pattern. 1. The `Logger` class that callers interact with doesn’t itself implement either filtering or output. Instead, it maintains a list of filters and a list of handlers. 2. For each log message, the logger calls each of its filters. The message is discarded if any filter rejects it. 3. For each log message that’s accepted by all the filters, the logger loops over its output handlers and asks every one of them to `emit()` the message. [View Highlight](https://read.readwise.io/read/01j8r76se8wen2j1m7g91bgp89)) a logger’s messages might deserve both multiple filters *and* multiple outputs — to decouple filter classes and handler classes entirely [View Highlight](https://read.readwise.io/read/01j8r77jrx6spm326k65g9w54d)) design principles like Composition Over Inheritance are, in the end, more important than individual patterns like the Adapter or Decorator. Always follow the principle. But don’t always feel constrained to choose a pattern from an official list. [View Highlight](https://read.readwise.io/read/01j8sgr5es60teb6y127ycdjnw)) Sometimes, yes, you will find an existing Design Pattern that’s a perfect fit for your problem — but if not, your design might be stronger if you move beyond them. [View Highlight](https://read.readwise.io/read/01j8sgsc3731bd5qq2fxm6ww5e)) I suggest that the apparent simplicity of the `if` statement forest is, from the point of view of software design, largely an illusion. [View Highlight](https://read.readwise.io/read/01j8sh7a9e0mf63x6r2fqpemh5))