The overall pattern catalog. The goals of this enterprise are admittedly audacious: to not only re-visit the original Gang-of-Four patterns, bringing them "up to speed" with modern languages and idioms, but also to incorporate concepts from functional (and object/functional hybrid) languages.
Note that these are "design patterns", meaning they are at the level of software implementation design, not "architectural" patterns (such as what we might find from Martin Fowler's "Patterns of Enterprise Application Architecture").
This roughly follows the same format as the original Gang-of-Four patterns catalog, but with a few changes.
-
The original patterns are not duplicated in their entirety*. This is deliberate, in that I wish to avoid any copyright infringement and I want to encourage those who have not read the original book to procure a copy and do so.
-
The patterns are cast into a "simpler" form.* Rather than the long form the GOF used, I have chosen to try and "simplify" the patterns by following a Problem/Solution/Context/Consequences format, with particular emphasis on Context and Consequences. A few Variations on the patterns have emerged over time, so I try to capture those, as well.
-
Some additional patterns are described here.
-
In seeking to bring the patterns up to "modern times" and languages, I have chosen to add a few more patterns that I think we have discovered along the way. These, in particular, should be treated with some level of skepticism and suspicion, as they have not been properly workshopped. Additionally, I will be going back through much of my patterns library and looking for additional patterns that seem to fit the rough category the GOF book occupied, and add them here (again, with some level of modernizing, if necessary).
This catalog is a continual work-in-progress; as more patterns are added to the catalog, their links will become active. Readers are encouraged to comment liberally, provide alternative implementations and/or suggest different language-specfic idioms, and/or participate in whatever fashion feels meaningful.
By the way, this will take time to flesh everything out, so please, be patient. I promise I'm trying to get to these as fast as I can without doing an ugly job of it.
The full index is at the bottom of this page, along with the implementations (in a separate list below that).
Patterns which describe the runtime relationship between one entity and another, and the flow of control between them.
Patterns which specifically deal with the creation of objects/entities in the code.
Patterns which describe the structural (usually compile-time-related, in langauges which are compiled) relationship between one entity and another.
Patterns which describe how to execute operations in parallel and safeguard them from the various dangers that arise from doing so.
I believe that some patterns are, in fact, combinations/compositions of other patterns, and so I want to take a stab at capturing and analyzing them. (I think a number of Fowler's PEAA and the POSA books are made up of some other patterns, arranged in a particular way but interesting and useful nonetheless.)
A number of patterns "widen" well, operating either at the class/design level or at a larger scope (such as a distributed system). I'm personally not entirely sure of the parameters around an architectural pattern, or if an architectural pattern is a design pattern, particularly when I can see some architectural patterns being reasonable design patterns and vice versa, but I'll capture them and refactor later as inspiration/illumination strikes.
A bibliographic reference to all/many/most of the patterns in the catalog, in case anybody wants to get the original texts.
Additional pattern language(s)
I'd like to capture all of these together into a larger pattern language/fabric.
-
Pattern-Oriented Software Architecture, vol 1
- Whole-Part (structural): aggregations of components that together form a semantic unit
Master-Slave (combine this with Leader-Followers, from POSA2) (behavioral): a master component distributes work to identical slave components and computers a final result from the results these slaves return.
Proxy
Command Processor (definitely GOF-Command)
- View Handler (sounds like a Chain of Responsibility/Observer hybrid)
- Counted Pointer (structural) (this is an idiom for C++, but the idea of objects "carrying" additional information about themselves to provide additional functionality feels too commmon to be just a variant on Proxy)
Forwarder-Receiver (aka proxy/stub from DCOM or CORBA stubs/skeletons; definitely a Proxy variant)
Client-Dispatcher-Server: provides location transparency by means of a name service and hides the details of the establishment of the communication connection between clients and servers (seems like a combination of a Registry and Proxy/Forwarder-Receiver)
- Publisher-Subscriber (variant of Chain of Responsibility? variant of Pipes-and-filters?)
- Layers: structure applications that can be decomposed into groups of subtasks in which each group of subtasks is at a particular level of abstraction; (structural?)
- Pipes and filters: a structure for systems that process a stream of data (structural?)
- Blackboard: useful for problems for which no deterministic solution strategies are known (behavioral)
- Broker (feels like a combination of multiple patterns)
- Model-View-Controller: divides an interactive application into three components: core functionality, representation, and control, with a change-propagation mechanism to ensure consistency between the three parts (definitely feels like GOF-Observer/Chain-of-Responsibility hybrid)
- Presentation-Abstraction-Control: defines a structure for interactive software systems in the form of a hierarchy of cooperating agents, each of which is responsible for a specific aspect of the application's functionality, principally built out of three components (presentation of information, abstraction, and control). (this is different from MVC even though it's similar)
- Microkernel: separates a minimal functional core from extended functionality and customer-specific parts
Reflection: changing structure and behavior of software systems dynamically, supporting the modification of fundamental aspects, such as type structures and function call mechanisms. (This is a DynamicObject, unless its provided by the underlying language/platform directly)
-
Pattern-Oriented Software Architecture, vol 2 (Patterns for Concurrent and Networked Objects)
- Wrapper Facade (structural)
- Component Configuration (creational)
- Interceptor (structural)
- Extension Interface (structural)
- Reactor
- Proactor
- Asynchronous Completion Token
- Acceptor-Connector
- Scoped Locking (originally presented as a C++ idiom relying on C++'s "RAII" (Resource Acquisition Is Initialization) behavior around determinstic constructors and destructors; not sure if it generalizes well beyond that)
- Strategized Locking
- Thread-Safe Interface
Double-Checked Locking Optimization (this has been proven over and over again to be a naive optimization given insufficient memory model guarantees to prevent out-of-order execution)
- Active Object
- Monitor Object
- Half-Sync/Half-Async
- Leader/Followers
Thread-Specific Storage (really, this is a thread-specific Context Object)
The first four are categorized there as "Service Access and Configuration"; the next four, "Event Handling". "Sychronization" covers Scoped Locking, Strategized Locking, Thread-Safe Interface and Double-Checked, and "Concurrency" captures the remaining five.
-
Envoy This is a set of patterns around how to accomplish various functional ideas. The author originally demonstrated all of his examples in Scheme; a while back I blogged about how to implement the patterns in a few other languages. I fully intend to examine each of these and think about where they fit in the above, or, if not, what the new category should be.
- Function as Object (almost certainly a synonym for Strategy in its simplest form, or vice versa, depending on how we want to look at it.)
- Closure (I'm calling this "Closure-Based State")
- Constructor Function
- Method Selector (A method selector is essentially the ability to identify and pass around an identifier to a method directly--a method pointer, function reference, or delegate, depending on your choice of platform--and inoke it. Many languages have this built in, but there's some nuance to the pattern here that deserves examination, as well.)
- Message-Passing Interface
- Generic Function
- Delegation
- Private Method (This is probably an idiom for functional languages, not a full pattern, per se; it is built-in syntax for most object-oriented languages, and many languages that support nested-scope functions/procedures can do something similar.)
-
Kuhne's "Functional Pattern System for Object-Oriented Design": Thomas Kuhne wrote his thesis (the above title) on patterns of functional style in OO systems, and his patterns would seem to have direct bearing on this effort. (I was fortunate enough to see an early draft of the work back in the late 90's, and his hand-signed copy of the printed thesis is one of my book treasures.) Again, I'll look for ways to incorporate them into the larger collection here.
- Function Object (like the Function as Object from Envoy, I think this is a Strategy or something similar to it)
- Lazy Object
- Value Object
- Transfold
- Void Value
- Translator
-
Monads/monoids. These staples of the functional community seem, to me, to be patterns, but with a bit more rigor implied to them. "Arrows" may be in a similar category.
-
Data Access Patterns (DAP): This was published in the early 2000s, during the peak of the patterns wave, and captured a lot of the common thinking around data access (particularly relational data access) at the time. Many of these patterns, I think are compositional in nature, but a few feel a little novel and/or bring a different perspective, and are worth capture.
- Data Accessor
- Active Domain Object
- Object/Relational Map
- Layers
- Resource Decorator
- Resource Pool
- Resource Timer
- Resource Descriptor
- Retryer
- Selection Factory
- Domain Object Factory
- Update Factory
- Domain Object Assembler
- Paging Iterator
- Cache Accessor
- Demand Cache
- Primed Cache
- Cache Search Sequence
- Cache Collector
- Cache Replicator
- Cache Statistics
- Transaction
- Optimistic Lock
- Pessimistic Lock
- Compensating Transaction
I also plan to go back through some of my patterns books (such as the "Pattern Languages of Program Design" books that were published in the late 90's/early 00's) and cherry-pick some that seem to fit in the above categorization scheme.
In other words, this is going to be a long work in progress.
Implementations
I have notes around the different pattern implementations (and the languages in which I am choosing to do them) here. However, the implementations will always appear in a separate page from the pattern itself, owing to the fact that (a) I want to explore several languages around each pattern, and it would make each pattern page extremely long to have them all in one place, but also (b) patterns can and should be language-independent, and therefore it makes sense to me to split them apart.
(Back to the
main catalog.)
Index
- Abstract Factory: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
- Adapter: TODO
- Blackboard: Defines a mechanic by which individualized components each solve a portion of an otherwise non-deterministic solution to collectively come up with a solution.
- Bridge: TODO
- Builder: Separate the construction of a complex object from its representation so that the same construction process can create different representations.
- Chain of Responsibility: Avoid coupling the sender of a request to its receiver by giving more than one component a chance to handle the request by chaining the receiving components and passing the request along the chain until one handles it.
- Closure-Based State: Use the scoping mechanisms of closures to provide a means for storing state outside of, but still available to, an object.
- Closure-based State: F#: A Closure-based State implementation in F#.
- Command: (TODO)
- Composite: TODO
- Constructor Function: Define an easy interface for creating an object, but defer the actual decision of what object type to instantiate.
- Context Object: Use an object to provide some degree of inference or reference about the environment in which another object or group of objects is operating.
- Continuation Chain: (TODO)
- Decorator: TODO
- Dynamic Object: An object whose structure and contents change over time without requiring any sort of change in code.
- Extension Interface: (TODO)
- Facade: TODO
- Factory Method: Define an interface for creating an object, but let something (usually subclasses, but not always) decide which object type to instantiate.
- Flyweight: TODO
- Interceptor: Provide additional functionality to an existing component by "intercepting" a request to the component and either replacing or supplementing the component's behavior.
- Interpreter: (TODO)
- Iterator: (TODO)
- Layers: TODO
- Mediator: Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
- Memento: Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
- Message-Passing Interface: Define an interface for a component that takes a message (a name and a variable number of named values) and processes it, either synchronously or asynchronously.
- Microkernel: (TODO)
- Null Object (aka Option): Provide a default behavior/implementation for the "null" or "undefined" case for a given object or class.
- Observer: (TODO)
- Pattern Implementations: Notes about some implementations of various patterns, in various languages.
- Pipes and Filters: Defines a structure for systems that process a stream of data using individualized components that can be arranged in a variety of different ways.
- Prototype: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
- Proxy: Provide a surrogate or placeholder for another object to control access to it.
- Service Locator: (TODO)
- Singleton: Ensure only one instance of a given type, and provide a global point of access to it.
- State: (TODO)
- Strategy (aka Function Object): (TODO)
- Template Method: (TODO)
- Value Object: Some objects represent values and have no intrinsic sense of identity or uniqueness. As such, these objects must present different semantics around their use.
- Visitor: (TODO)
- Whole-Part: Helps with the aggregation of components that together form a semantic unit.
- Wrapper Facade (aka Wrapper): Provide a "surface area" interface to an otherwise more complex underlying API so that callers can remain conveniently ignorant of the details.
Implementations
javascript
csharp
fsharp
java
scala
kotlin
swift