In music, it’s the chorus of a song; in medicine, it’s the heart rate; for a criminal, it's modus operandi, or their method of operation; in graphics, it’s repeating design elements (like the Arabic script in Islamic culture), and in mathematics…
Formulas in mathematics (and physics) are also a kind of pattern, into which the diversity of life can be substituted—from apples added in first grade to processes in the quantum world.
A mathematician was once given a problem: there is water, a stove, matches, and a kettle. The task is to boil water. The mathematician provides the standard solution: pour water into the kettle, light the stove, place the kettle on the flame.
Then, a second problem is posed: everything is the same, but the stove is already lit. The mathematician responds that the fire should be extinguished and then return to the previously solved problem. In other words, go back to the pattern.
Mathematics, or more precisely, Boolean algebra, has led to the development of the entire world of programming.
Advantages of using patterns in programming:
- Speed up the coding process
- Help avoid errors due to negligence or randomness, as a standard set of code is used
- Makes it easier for an external developer familiar with patterns to understand the code
Downsides:
- A pattern might make the code longer; in the story about the mathematician, an extra operation had to be performed.
Main groups of patterns:
- Creational – templates that organize the creation of objects
- Structural – templates that combine objects and their classes into structures
- Behavioral – organize interaction with external objects relative to our system
Creational Patterns:
Used when objects from the same group need to be created but solve different tasks. For example, a bank-client program provides a personal account for a bank representative, administrator, company director, and company accountant. Each has different functionality, but the purpose is the same—a personal account.
Types of Creational Patterns:
Singleton – creates an object or group of objects and provides access to it
Builder – implements a method of creating a composite object, abstracting from the nature of the objects.
Prototype - defines the types of objects to be created using a prototype instance and creates new objects by copying this prototype.
Factory Method – allows subclasses of objects to create a higher-level class.
Abstract factory – provides an interface for creating families of objects without specifying their concrete classes.
Object pool – a set of objects ready for use. When a system needs an object, it is taken from the pool rather than created.
Structural Patterns:
They combine systems into more complex structures and support class hierarchies. For example, if you need to connect several incompatible plugins to a system, a structural pattern solves this task.
Types of Structural Patterns:
Decorator – dynamically attaches new functionality to objects, expanding their capabilities.
Facade - provides a simple interface to a complex system of classes, a library, or a framework.
Bridge - separates one or more classes into two separate hierarchies—abstraction and implementation, allowing them to evolve independently.
Adapter – allows incompatible interfaces to work together.
Composite - groups multiple objects into a tree structure and works with it as a single object.
Proxy – intercepts access to an object, allowing the request to be processed before passing it to the original.
Flyweight – minimizes the use of memory by sharing as much data as possible.
Behavioral Patterns:
These define algorithms for interaction between various objects, groups, and classes. They structure the interaction between objects, making it easier to maintain and modify.
Types of Behavioral Patterns:
Observer – establishes a dependency between objects so that when one object changes state, all dependent objects are automatically notified and updated.
State - allows an object to alter its behavior when its internal state changes.
Strategy - defines a set of algorithms that can be chosen during execution; the code selects the appropriate algorithm based on the given command.
Command - encapsulates information within an object, protecting it from potential changes.
Chain of Responsibility - creates a chain from a source of command objects and a group of processing objects. The processing object can handle the request according to its algorithm or pass it to the next object in the chain.
This article aims to draw attention to the use of patterns in code and serve as an aggregator for more detailed articles on the subject.
By following the links, you can explore code examples for each pattern mentioned in the article.
For further detailed study, the following books are recommended:
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994) Design Patterns: Elements of Reusable Object-Oriented Software
Freeman, Eric T.; Robson, Elisabeth; Bates, Bert; Sierra, Kathy (2004). Head First Design Patterns.
Hohpe, Gregor; Woolf, Bobby (2003). Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions.