OO Design Patterns

A Refresher/Introduction

In Object Oriented programming, design patterns build upon OO pillars and principles to provide time-tested general solutions to design problems. Patterns yield good OO qualities such as reusability, maintainability and extensibility.

Developers who are familiar with design patterns can communicate more effectively and concisely as patterns form a shared vocabulary.

Pattern trade-offs

The adoption of a pattern may have downsides as patterns can introduce a layer of complexity and abstraction to code bases. Therefore developers are best to utilize a combination of technical and domain knowledge to identify areas of frequent change or genuine extensibility requirements before introducing patterns into code bases. This allows for patterns to be utilized where most needed rather than add unnecessary complexities with only perceived benefits.

Not every problem should be resolved via pattern implementation, therefore developers need not suffer pattern fever by attempting to utilize patterns in every implementation. It is advisable to aim for the simplest solution possible even if that solution does not implement a pattern, on the other hand, a solution may be made simpler via pattern adoption.

Each pattern offers a trade-off, developers must carefully study trade-offs before settling for a pattern to resolve a design problem, trade-offs may appear in different forms such as abstraction vs speed or space versus time.

Anti-patterns

An anti-pattern provides a bad solution to a problem, the bad solution may be attractive but is counterproductive or ineffective.

A developer who is familiar with Anti-patterns can distinguish between good and bad design patterns. Anti-patterns are often documented to aid developers in recognizing them within code bases and avoiding them.

Design patterns

A few design patterns have been listed below, but the ultimate method to maintaining a reference to design patterns is via catalogs:

Factory: There are several variants of the Factory pattern however all revolve around encapsulating object creation to lead to more decoupled and flexible designs. Variants of the factory pattern include the Simple Factory, Abstract Factory and Factory Method.

Builder: Use the Builder Pattern to encapsulate the construction of a product and allow it to be constructed in steps.

Proxy: Provides a surrogate or placeholder for another object to control access to it. There are different variations of the proxy pattern such as remote proxy, virtual proxy and protection proxy to list a few.

Strategy: Defines a family of algorithms, encapsulates each one and makes them interchangeable. Strategy lets the algorithm vary independently from the client that uses it.

Decorator: attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Adapter: Converts the interface of a class into another interface clients expect, this allows for classes to work together that otherwise aren’t able to due to incompatible interfaces.

Facade: Provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

Iterator: Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Composite: Allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Null object: A null object is useful when you don’t have a meaningful object to return, and yet you want to remove the responsibility for handling null from the client.

Building a library of patterns

Developers who maintain a library of patterns within their minds can more easily understand pattern implementation and recognize the potential to adopt patterns to resolve problems they encounter or to be able to derive new patterns by extending existing patterns.

Naming conventions

Highlighting pattern names within naming conventions will aid developers in understanding how different components within an implementation hang together, and the role each component plays and will aid in ensuring future software changes are made appropriately.

An alternative to suffixing class names is to highlight the pattern which implementation is based upon within documentation.

Martin Fowler recommends integrating pattern names into naming conventions in his Clean Code book.

Design pattern catalogs

It serves every developer well to have access to a Design patterns catalog, these catalogs contain a compilation of patterns that developers can utilize as a reference either when on the hunt out for a solution or to refresh their knowledge.

Catalogs often divide patterns into categories allowing developers to locate patterns, each pattern will be supplemented by a definition, real-world usage examples and UML diagrams to aid the implementation and highlight structures which the pattern is based upon.

Several books have been authored on software design patterns, below are two of my favorites so far, I highly recommend that any developer reads these regardless of which level they are at within their career:

Design Patterns: Elements of Reusable Object-Oriented Software, contains over 20 design patterns that had a major influence on the software industry and patterns contained within form the basis of many modern-day patterns.

Head First: Design Patterns, is an incredibly easy and joyful book to read, filled with easily memorable information and easy-to-understand examples.

All of the information highlighted within this article is based on information derived from these books, therefore all credits go to their authors.