Compiled from Martin Fowler’s EAA catalog (published 5 March 2003; site design refreshed July 2024, content unchanged). Pattern text below is the catalog summary Fowler published for each pattern. Sketch GIFs on those pages are recreated here as Mermaid or ASCII diagrams.
The book Patterns of Enterprise Application Architecture is the full treatment. Each pattern links to the matching chapter on oreilly.com.
Fowler notes that many original Visio GIFs were later redrawn by David Heinemeier Hansson.
Five catalog pages have no sketch image: Client Session State, Server Session State, Database Session State, Layer Supertype, and Value Object. Those five use a reconstructed diagram marked as such.
- Domain Logic Patterns
- Data Source Architectural Patterns
- Object-Relational Behavioral Patterns
- Object-Relational Structural Patterns
- Object-Relational Metadata Mapping Patterns
- Web Presentation Patterns
- Distribution Patterns
- Offline Concurrency Patterns
- Session State Patterns
- Base Patterns
Enterprise applications are about the display, manipulation, and storage of large amounts of often complex data; together with the support or automation of business processes with that data. Examples include reservation systems, financial systems, supply chain systems, and many others that run modern business. Enterprise applications have their own particular challenges and solutions, and they are different from embedded systems, control systems, telecoms, or desktop productivity software.
The book collects patterns seen in these systems over the years. They include layering, structuring business logic, structuring a web user interface, linking in-memory data to a relational database, and handling session state in stateless environments.
Intent: Organizes business logic by procedures where each procedure handles a single request from the presentation.
Source: catalog page · Chapter 09
The catalog sketch is a single operations box (no class name) for revenue-recognition procedures:
classDiagram
class TransactionScript {
recognizedRevenue(contractNumber: long, asOf: Date) Money
calculateRevenueRecognitions(contractNumber: long) void
}
Most business applications can be thought of as a series of transactions. A transaction may view some information as organized in a particular way, another will make changes to it. Each interaction between a client system and a server system contains a certain amount of logic. In some cases this can be as simple as displaying information in the database. In others it may involve many steps of validations and calculations.
A Transaction Script organizes all this logic primarily as a single procedure, making calls directly to the database or through a thin database wrapper. Each transaction will have its own Transaction Script, although common subtasks can be broken into subprocedures.
Intent: An object model of the domain that incorporates both behavior and data.
Source: catalog page · Chapter 09
classDiagram
class Contract {
recognizedRevenue(date)
calculateRecognitions()
}
class Product {
calculateRecognitions(contract)
}
class RecognitionStrategy {
<<abstract>>
}
class CompleteRecognitionStrategy
Contract --> Product : 1
Product --> RecognitionStrategy : 1
RecognitionStrategy <|-- CompleteRecognitionStrategy
Contract ..> Database
Product ..> Database
class Database {
<<datastore>>
}
At its worst business logic can be very complex. Rules and logic describe many different cases and slants of behavior, and it's this complexity that objects were designed to work with. A Domain Model creates a web of interconnected objects, where each object represents some meaningful individual, whether as large as a corporation or as small as a single line on an order form.
Intent: A single instance that handles the business logic for all rows in a database table or view.
Source: catalog page · Chapter 09
One class per table; each instance talks to the database:
classDiagram
class Contract {
recognizeRevenue(id)
}
class Product {
getProductType(id)
}
class RevenueRecognition {
insert(id)
recognizedRevenue(contractId, date)
}
class Database {
<<datastore>>
}
Contract ..> Database
Product ..> Database
RevenueRecognition ..> Database
One of the key messages of object orientation is bundling the data with the behavior that uses it. The traditional object-oriented approach is based on objects with identity, along the lines of Domain Model. Thus, if we have an Employee class, any instance of it corresponds to a particular employee. This scheme works well because once we have a reference to an employee, we can execute operations, follow relationships, and gather data on him.
One of the problems with Domain Model is the interface with relational databases. In many ways this approach treats the relational database like a crazy aunt who's shut up in an attic and whom nobody wants to talk about. As a result you often need considerable programmatic gymnastics to pull data in and out of the database, transforming between two different representations of the data.
A Table Module organizes domain logic with one class per table in the database, and a single instance of a class contains the various procedures that will act on the data. The primary distinction with Domain Model is that, if you have many orders, a Domain Model will have one order object per order while a Table Module will have one object to handle all orders.
Intent: Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.
Source: catalog page · Chapter 09
The catalog sketch is concentric rings (data source inside domain model inside service layer), with three client kinds on the outside:
flowchart TB
DL[Data Loaders] --> SL
UI[User Interfaces] --> SL
IG[Integration Gateway] --> SL
subgraph SL[Service Layer]
RS[RecognitionService]
subgraph DM[Domain Model]
DS[(Data Source Layer)]
end
end
Enterprise applications typically require different kinds of interfaces to the data they store and the logic they implement: data loaders, user interfaces, integration gateways, and others. Despite their different purposes, these interfaces often need common interactions with the application to access and manipulate its data and invoke its business logic. The interactions may be complex, involving transactions across multiple resources and the coordination of several responses to an action. Encoding the logic of the interactions separately in each interface causes a lot of duplication.
A Service Layer defines an application's boundary and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coordinating responses in the implementation of its operations.
Intent: An object that acts as a gateway to a database table. One instance handles all the rows in the table.
Source: catalog page · Chapter 10
classDiagram
class Person {
lastName
firstName
numberOfDependents
}
class PersonGateway {
find(id)
findForCompany(companyId)
update(id, lastName, firstName, numberOfDependents)
insert(lastName, firstName, numberOfDependents)
}
Person ..> PersonGateway
Mixing SQL in application logic can cause several problems. Many developers aren't comfortable with SQL, and many who are comfortable may not write it well. Database administrators need to be able to find SQL easily so they can figure out how to tune and evolve the database.
A Table Data Gateway holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database.
Intent: An object that acts as a gateway to a single record in a data source. There is one instance per row.
Source: catalog page · Chapter 10
Finder plus one gateway instance per row:
classDiagram
class PersonFinder {
find(id)
findForCompany(companyId)
}
class Person {
lastName
firstName
numberOfDependents
}
class PersonGateway {
lastName
firstName
numberOfDependents
insert()
update()
}
PersonFinder ..> PersonGateway
Person ..> PersonGateway
Embedding database access code in in-memory objects can leave you with a few disadvantages. For a start, if your in-memory objects have business logic of their own, adding the database manipulation code increases complexity. Testing is awkward too since, if your in-memory objects are tied to a database, tests are slower to run because of all the database access. You may have to access multiple databases with all those annoying little variations on their SQL.
A Row Data Gateway gives you objects that look exactly like the record in your record structure but can be accessed with the regular mechanisms of your programming language. All details of data source access are hidden behind this interface.
Intent: An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.
Source: catalog page · Chapter 10
classDiagram
class Person {
lastName
firstName
numberOfDependents
insert()
update()
getExemption()
isFlaggedForAudit()
getTaxableEarnings()
}
class Database {
<<datastore>>
}
Person ..> Database
An object carries both data and behavior. Much of this data is persistent and needs to be stored in a database. Active Record uses the most obvious approach, putting data access logic in the domain object. This way all people know how to read and write their data to and from the database.
Intent: A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.
Source: catalog page · Chapter 10
The mapper knows both sides; the domain object does not know the database:
classDiagram
class Person {
lastName
firstName
numberOfDependents
getExemption()
isFlaggedForAudit()
getTaxableEarnings()
}
class PersonMapper {
insert()
update()
delete()
}
class Database {
<<datastore>>
}
PersonMapper ..> Person
PersonMapper ..> Database
Objects and relational databases have different mechanisms for structuring data. Many parts of an object, such as collections and inheritance, aren't present in relational databases. When you build an object model with a lot of business logic it's valuable to use these mechanisms to better organize the data and the behavior that goes with it. Doing so leads to variant schemas; that is, the object schema and the relational schema don't match up.
You still need to transfer data between the two schemas, and this data transfer becomes a complexity in its own right. If the in-memory objects know about the relational database structure, changes in one tend to ripple to the other.
The Data Mapper is a layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data between the two and also to isolate them from each other. With Data Mapper the in-memory objects needn't know even that there's a database present; they need no SQL interface code, and certainly no knowledge of the database schema. (The database schema is always ignorant of the objects that use it.) Since it's a form of Mapper, Data Mapper itself is even unknown to the domain layer.
Intent: Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
Source: catalog page · Chapter 11
classDiagram
class UnitOfWork {
registerNew(object)
registerDirty(object)
registerClean(object)
registerDeleted(object)
commit()
rollback()
}
When you're pulling data in and out of a database, it's important to keep track of what you've changed; otherwise, that data won't be written back into the database. Similarly you have to insert new objects you create and remove any objects you delete.
You can change the database with each change to your object model, but this can lead to lots of very small database calls, which ends up being very slow. Furthermore it requires you to have a transaction open for the whole interaction, which is impractical if you have a business transaction that spans multiple requests. The situation is even worse if you need to keep track of the objects you've read so you can avoid inconsistent reads.
A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.
Intent: Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them.
Source: catalog page · Chapter 11
sequenceDiagram
autonumber
participant Caller
participant finder
participant map as an identity map
participant database
Caller->>finder: find(1)
finder->>map: found = get(1)
alt found not null
finder-->>Caller: found
else found is null
finder->>database: found = select where id = 1
finder-->>Caller: found
end
An old proverb says that a man with two watches never knows what time it is. If two watches are confusing, you can get in an even bigger mess with loading objects from a database. If you aren't careful you can load the data from the same database record into two different objects. Then, when you update them both you'll have an interesting time writing the changes out to the database correctly.
Related to this is an obvious performance problem. If you load the same data more than once you're incurring an expensive cost in remote calls. Thus, not loading the same data twice doesn't just help correctness, but can also speed up your application.
An Identity Map keeps a record of all objects that have been read from the database in a single business transaction. Whenever you want an object, you check the Identity Map first to see if you already have it.
Intent: An object that doesn't contain all of the data you need but knows how to get it.
Source: catalog page · Chapter 11
sequenceDiagram
participant Caller
participant customer as a customer
participant db as the database
Caller->>customer: get orders
alt orders not loaded
customer->>db: load orders
end
customer-->>Caller: return orders
For loading data from a database into memory it's handy to design things so that as you load an object of interest you also load the objects that are related to it. This makes loading easier on the developer using the object, who otherwise has to load all the objects he needs explicitly.
However, if you take this to its logical conclusion, you reach the point where loading one object can have the effect of loading a huge number of related objects — something that hurts performance when only a few of the objects are actually needed.
A Lazy Load interrupts this loading process for the moment, leaving a marker in the object structure so that if the data is needed it can be loaded only when it is used. As many people know, if you're lazy about doing things you'll win when it turns out you don't need to do them at all.
Note (from the catalog): There are four main varieties of lazy load.
- Lazy Initialization uses a special marker value (usually null) to indicate a field isn't loaded. Every access to the field checks the field for the marker value and if unloaded, loads it.
- Virtual Proxy is an object with the same interface as the real object. The first time one of its methods are called it loads the real object and then delegates.
- Value Holder is an object with a
getValuemethod. Clients callgetValueto get the real object; the first call triggers the load. - Ghost is the real object without any data. The first time you call a method the ghost loads the full data into its fields.
These approaches vary somewhat subtly and have various trade-offs. You can also use combination approaches. The book contains the full discussion and examples.
Intent: Saves a database ID field in an object to maintain identity between an in-memory object and a database row.
Source: catalog page · Chapter 12
classDiagram
class Person {
id : long
}
Relational databases tell one row from another by using a key — in particular, the primary key. However, in-memory objects don't need such a key, as the object system ensures the correct identity under the covers (or in C++'s case with raw memory locations). Reading data from a database is all very well, but in order to write data back you need to tie the database to the in-memory object system.
In essence, Identity Field is mind-numbingly simple. All you do is store the primary key of the relational database table in the object's fields.
Intent: A structure to organize database mappers that handle inheritance hierarchies.
Source: catalog page · Chapter 12
classDiagram
class Mapper {
+insert(DomainObject)
+update(DomainObject)
+delete(DomainObject)
-- hook methods --
#save(DomainObject, Row)
#load(DomainObject, Row)
}
class PlayerMapper {
+find(key) Player
+insert()
+update()
}
class AbstractPlayerMapper {
#save()
#load()
}
class FootballerMapper {
+find(key) Footballer
#save()
#load()
}
class CricketerMapper {
+find(key) Cricketer
#save()
#load()
}
class BowlerMapper {
+find(key) Bowler
#save()
#load()
}
Mapper <|-- PlayerMapper
Mapper <|-- AbstractPlayerMapper
AbstractPlayerMapper <|-- FootballerMapper
AbstractPlayerMapper <|-- CricketerMapper
CricketerMapper <|-- BowlerMapper
PlayerMapper o--> FootballerMapper
PlayerMapper o--> CricketerMapper
PlayerMapper o--> BowlerMapper
When you map from an object-oriented inheritance hierarchy in memory to a relational database you have to minimize the amount of code needed to save and load the data to the database. You also want to provide both abstract and concrete mapping behavior that allows you to save or load a superclass or a subclass.
Although the details of this behavior vary with your inheritance mapping scheme (Single Table Inheritance, Class Table Inheritance, and Concrete Table Inheritance) the general structure works the same for all of them.
Intent: Maps an association between objects to a foreign key reference between tables.
Source: catalog page · Chapter 12
classDiagram
class Album {
title : string
}
class Artist {
name : string
}
Album --> Artist : 1
class Albums {
<<table>>
id : int
title : varchar
artistId : int
}
class Artists {
<<table>>
id : int
name : varchar
}
Objects can refer to each other directly by object references. Even the simplest object-oriented system will contain a bevy of objects connected to each other in all sorts of interesting ways. To save these objects to a database, it's vital to save these references. However, since the data in them is specific to the specific instance of the running program, you can't just save raw data values. Further complicating things is the fact that objects can easily hold collections of references to other objects. Such a structure violates the first normal form of relational databases.
A Foreign Key Mapping maps an object reference to a foreign key in the database.
Intent: Saves an association as a table with foreign keys to the tables that are linked by the association.
Source: catalog page · Chapter 12
classDiagram
class Employee
class Skill
Employee --> Skill
class Employees {
<<table>>
id
}
class skill_employees {
<<table>>
employeeId
skillId
}
class Skills {
<<table>>
id
}
Objects can handle multivalued fields quite easily by using collections as field values. Relational databases don't have this feature and are constrained to single-valued fields only. When you're mapping a one-to-many association you can handle this using Foreign Key Mapping, essentially using a foreign key for the single-valued end of the association. But a many-to-many association can't do this because there is no single-valued end to hold the foreign key.
The answer is the classic resolution that's been used by relational data people for decades: create an extra table to record the relationship. Then use Association Table Mapping to map the multivalued field to this link table.
Intent: Has one class perform the database mapping for a child class.
Source: catalog page · Chapter 12
classDiagram
class Album
class Track {
title
}
class AlbumMapper
class Database {
<<datastore>>
}
Album *--> Track : ordered
AlbumMapper ..> Album
AlbumMapper ..> Track
AlbumMapper ..> Database
Some objects naturally appear in the context of other objects. Tracks on an album may be loaded or saved whenever the underlying album is loaded or saved. If they aren't referenced to by any other table in the database, you can simplify the mapping procedure by having the album mapper perform the mapping for the tracks as well — treating this mapping as a dependent mapping.
Intent: Maps an object into several fields of another object's table.
Source: catalog page · Chapter 12
classDiagram
class Employment {
id
person : Person
period : DateRange
salary : Money
}
class Employments {
<<table>>
id : int
personId : int
start : date
end : date
salaryAmount : decimal
salaryCurrency : char
}
Many small objects make sense in an OO system that don't make sense as tables in a database. Examples include currency-aware money objects and date ranges. Although the default thinking is to save an object as a table, no sane person would want a table of money values.
An Embedded Value maps the values of an object to fields in the record of the object's owner. In the sketch we have an employment object with links to a date range object and a money object. In the resulting table the fields in those objects map to fields in the employment table rather than make new records themselves.
Intent: Saves a graph of objects by serializing them into a single large object (LOB), which it stores in a database field.
Source: catalog page · Chapter 12
classDiagram
class Customer
class Department
Customer "1" -- Department
Department "1" --> Department : parent
Department --> Department : children\n{hierarchy}
class Customers {
<<table>>
departments : BLOB
}
Object models often contain complicated graphs of small objects. Much of the information in these structures isn't in the objects but in the links between them. Consider storing the organization hierarchy for all your customers. An object model quite naturally shows the composition pattern to represent organizational hierarchies, and you can easily add methods that allow you to get ancestors, siblings, descendants, and other common relationships.
Not so easy is putting all this into a relational schema. The basic schema is simple — an organization table with a parent foreign key — however, its manipulation of the schema requires many joins, which are both slow and awkward.
Objects don't have to be persisted as table rows related to each other. Another form of persistence is serialization, where a whole graph of objects is written out as a single large object (LOB) in a table; this Serialized LOB then becomes a form of memento.
Intent: Represents an inheritance hierarchy of classes as a single table that has columns for all the fields of the various classes.
Source: catalog page · Chapter 12
classDiagram
class Player {
name
}
class Footballer {
club
}
class Cricketer {
battingAverage
}
class Bowler {
bowlingAverage
}
Player <|-- Footballer
Player <|-- Cricketer
Cricketer <|-- Bowler
class Players {
<<table>>
name
club
battingAverage
bowlingAverage
type
}
Relational databases don't support inheritance, so when mapping from objects to databases we have to consider how to represent our nice inheritance structures in relational tables. When mapping to a relational database, we try to minimize the joins that can quickly mount up when processing an inheritance structure in multiple tables. Single Table Inheritance maps all fields of all classes of an inheritance structure into a single table.
Intent: Represents an inheritance hierarchy of classes with one table for each class.
Source: catalog page · Chapter 12
classDiagram
class Player {
name
}
class Footballer {
club
}
class Cricketer {
battingAverage
}
class Bowler {
bowlingAverage
}
Player <|-- Footballer
Player <|-- Cricketer
Cricketer <|-- Bowler
class Players {
<<table>>
name
}
class Footballers {
<<table>>
club
}
class Cricketers {
<<table>>
battingAverage
}
class Bowlers {
<<table>>
bowlingAverage
}
A very visible aspect of the object-relational mismatch is the fact that relational databases don't support inheritance. You want database structures that map clearly to the objects and allow links anywhere in the inheritance structure. Class Table Inheritance supports this by using one database table per class in the inheritance structure.
Intent: Represents an inheritance hierarchy of classes with one table per concrete class in the hierarchy.
Source: catalog page · Chapter 12
Each concrete class gets a table that includes inherited fields:
classDiagram
class Player {
<<abstract>>
name
}
class Footballer {
club
}
class Cricketer {
battingAverage
}
class Bowler {
bowlingAverage
}
Player <|-- Footballer
Player <|-- Cricketer
Cricketer <|-- Bowler
class Footballers {
<<table>>
name
club
}
class Cricketers {
<<table>>
name
battingAverage
}
class Bowlers {
<<table>>
name
battingAverage
bowlingAverage
}
As any object purist will tell you, relational databases don't support inheritance — a fact that complicates object-relational mapping. Thinking of tables from an object instance point of view, a sensible route is to take each object in memory and map it to a single database row. This implies Concrete Table Inheritance, where there's a table for each concrete class in the inheritance hierarchy.
I'll confess to having had some difficulty naming this pattern. Most people think of it as leaf oriented since you usually have one table per leaf class in a hierarchy. Following that logic, I could call this pattern leaf table inheritance, and the term “leaf” is often used for this pattern. Strictly, however, a concrete class that isn't a leaf usually gets a table as well, so I decided to go with the more correct, if less intuitive term.
Intent: Holds details of object-relational mapping in metadata.
Source: catalog page · Chapter 13
classDiagram
class DataMap {
domainClass
tableName
}
class ColumnMap {
columnName
fieldName
}
DataMap *--> "*" ColumnMap
Much of the code that deals with object-relational mapping describes how fields in the database correspond to fields in in-memory objects. The resulting code tends to be tedious and repetitive to write. A Metadata Mapping allows developers to define the mappings in a simple tabular form, which can then be processed by generic code to carry out the details of reading, inserting, and updating the data.
Intent: An object that represents a database query.
Source: catalog page · Chapter 13
classDiagram
class Query
class Criteria1 {
<<Criteria>>
operator = ">"
field = "numberOfDependents"
value = 0
}
class Criteria2 {
<<Criteria>>
operator = "="
field = "lastName"
value = "fowler"
}
Query *--> Criteria1
Query *--> Criteria2
SQL can be an involved language, and many developers aren't particularly familiar with it. Furthermore, you need to know what the database schema looks like to form queries. You can avoid this by creating specialized finder methods that hide the SQL inside parameterized methods, but that makes it difficult to form more ad hoc queries. It also leads to duplication in the SQL statements should the database schema change.
A Query Object is an interpreter, that is, a structure of objects that can form itself into a SQL query. You can create this query by referring to classes and fields rather than tables and columns. In this way those who write the queries can do so independently of the database schema and changes to the schema can be localized in a single place.
Intent: Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
Source: catalog page · Chapter 13
sequenceDiagram
participant client
participant aCriteria
participant repo as the repository
participant strategy as in memory strategy
participant person as a Person
client->>aCriteria: new
client->>aCriteria: equal(this, BENEFACTOR)
client->>repo: matching(aCriteria)
repo->>strategy: matching(aCriteria)
loop each person
strategy->>person: satisfies(aCriteria)
end
strategy-->>repo: people who satisfied the criteria
repo-->>client: people
A system with a complex domain model often benefits from a layer, such as the one provided by Data Mapper, that isolates domain objects from details of the database access code. In such systems it can be worthwhile to build another layer of abstraction over the mapping layer where query construction code is concentrated. This becomes more important when there are a large number of domain classes or heavy querying. In these cases particularly, adding this layer helps minimize duplicate query logic.
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
You can also find a good write-up of this pattern in Domain-Driven Design.
Intent: Splits user interface interaction into three distinct roles.
Source: catalog page · Chapter 14
The catalog sketch is the three MVC roles:
classDiagram
class Controller
class View
class Model
Controller ..> Model
Controller ..> View
View ..> Model
Model View Controller (MVC) is one of the most quoted (and most misquoted) patterns around. It started as a framework developed by Trygve Reenskaug for the Smalltalk platform in the late 1970s. Since then it has played an influential role in most UI frameworks and in the thinking about UI design.
Intent: An object that handles a request for a specific page or action on a Web site.
Source: catalog page · Chapter 14
classDiagram
class PageController {
-- handle HTTP get and post
-- decide which model and view to use
}
class Model {
-- domain logic
}
class View {
-- display HTML
}
PageController ..> Model
PageController ..> View
View ..> Model
Most people's basic Web experience is with static HTML pages. When you request static HTML you pass to the Web server the name and path for a HTML document stored on it. The key notion is that each page on the Web site is a separate document on the server. With dynamic pages things can get much more interesting since there's a much more complex relationship between path names and the file that responds. However, the approach of one path leading to one file that handles the request is a simple model to understand.
As a result, Page Controller has one input controller for each logical page of the Web site. That controller may be the page itself, as it often is in server page environments, or it may be a separate object that corresponds to that page.
Intent: A controller that handles all requests for a Web site.
Source: catalog page · Chapter 14
classDiagram
class Handler {
<<abstract>>
doGet()
doPost()
}
class Command {
<<abstract>>
process()
}
class ConcreteCommand1 {
process()
}
class ConcreteCommand2 {
process()
}
Handler ..> Command
Command <|-- ConcreteCommand1
Command <|-- ConcreteCommand2
In a complex Web site there are many similar things you need to do when handling a request. These things include security, internationalization, and providing particular views for certain users. If the input controller behavior is scattered across multiple objects, much of this behavior can end up duplicated. Also, it's difficult to change behavior at runtime.
The Front Controller consolidates all request handling by channeling requests through a single handler object. This object can carry out common behavior, which can be modified at runtime with decorators. The handler then dispatches to command objects for behavior particular to a request.
Intent: Renders information into HTML by embedding markers in an HTML page.
Source: catalog page · Chapter 14
flowchart LR
subgraph Model
Book
Author
end
Helper["Book Helper\ngetTitle\ngetAuthor"]
JSP["HTML template\njsp:getProperty bookHelper title\nAuthor:\njsp:getProperty bookHelper author"]
JSP -.-> Helper
Helper -.-> Model
Writing a program that spits out HTML is often more difficult than you might imagine. Although programming languages are better at creating text than they used to be (some of us remember character handling in Fortran and standard Pascal), creating and concatenating string constructs is still painful. If there isn't much to do, it isn't too bad, but a whole HTML page is a lot of text manipulation.
With static HTML pages — those that don't change from request to request — you can use nice WYSIWYG editors. Even those of us who like raw text editors find it easier to just type in the text and tags rather than fiddle with string concatenation in a programming language.
Of course the issue is with dynamic Web pages — those that take the results of something like database queries and embed them into the HTML. The page looks different with each result, and as a result regular HTML editors aren't up to the job.
The best way to work is to compose the dynamic Web page as you do a static page but put in markers that can be resolved into calls to gather dynamic information. Since the static part of the page acts as a template for the particular response, I call this a Template View.
Intent: A view that processes domain data element by element and transforms it into HTML.
Source: catalog page · Chapter 14
flowchart LR
subgraph Model
Album
Artist
end
T["Transformer\ntransformAlbum\ntransformArtist"]
HTML[HTML]
T -.->|read| Model
T -.->|creates| HTML
When you issue requests for data to the domain and data source layers, you get back all the data you need to satisfy them, but without the formatting you need to make a proper Web page. The role of the view in Model View Controller is to render this data into a Web page. Using Transform View means thinking of this as a transformation where you have the model's data as input and its HTML as output.
Intent: Turns domain data into HTML in two steps: first by forming some kind of logical page, then rendering the logical page into HTML.
Source: catalog page · Chapter 14
flowchart TB
Album["Album\nartist: Artist"]
S1["Stage 1\nrenderAlbum\nrenderArtist"]
Screen["Screen\nartist: Field"]
S2["Stage 2\nrenderScreen\nrenderField"]
HTML[HTML]
S1 -.->|read| Album
S1 -.->|create| Screen
S2 -.->|read| Screen
S2 -.->|create| HTML
If you have a Web application with many pages, you often want a consistent look and organization to the site. If every page looks different, you end up with a site that users find confusing. You may also want to make global changes to the appearance of the site easily, but common approaches using Template View or Transform View make this difficult because presentation decisions are often duplicated across multiple pages or transform modules. A global change can force you to change several files.
Two Step View deals with this problem by splitting the transformation into two stages. The first transforms the model data into a logical presentation without any specific formatting; the second converts that logical presentation with the actual formatting needed. This way you can make a global change by altering the second stage, or you can support multiple output looks and feels with one second stage each.
Intent: A centralized point for handling screen navigation and the flow of an application.
Source: catalog page · Chapter 14
sequenceDiagram
participant IC as an input controller
participant AC as an application controller
participant DC as a domain command
participant V as a view
Note over IC: request
IC->>AC: get domain command
IC->>DC: run
IC->>AC: get view
IC->>V: forward
Some applications contain a significant amount of logic about the screens to use at different points, which may involve invoking certain screens at certain times in an application. This is the wizard style of interaction, where the user is led through a series of screens in a certain order. In other cases we may see screens that are only brought in under certain conditions, or choices between different screens that depend on earlier input.
To some degree the various Model View Controller input controllers can make some of these decisions, but as an application gets more complex this can lead to duplicated code as several controllers for different screens need to know what to do in a certain situation.
You can remove this duplication by placing all the flow logic in an Application Controller. Input controllers then ask the Application Controller for the appropriate commands for execution against a model and the correct view to use depending on the application context.
Intent: Provides a coarse-grained facade on fine-grained objects to improve efficiency over a network.
Source: catalog page · Chapter 15
classDiagram
class AddressFacade {
getAddressData()
setAddress(street, city, zip)
}
class Address {
getStreet()
getCity()
getZip()
setStreet(arg)
setCity(arg)
setZip(arg)
}
AddressFacade ..> Address
In an object-oriented model, you do best with small objects that have small methods. This gives you lots of opportunity for control and substitution of behavior, and to use good intention revealing naming to make an application easier to understand. One of the consequences of such fine-grained behavior is that there's usually a great deal of interaction between objects, and that interaction usually requires lots of method invocations.
Within a single address space fine-grained interaction works well, but this happy state does not exist when you make calls between processes. Remote calls are much more expensive because there's a lot more to do: Data may have to be marshaled, security may need to be checked, packets may need to be routed through switches. If the two processes are running on machines on opposite sides of the globe, the speed of light may be a factor. The brutal truth is that any inter-process call is orders of magnitude more expensive than an in-process call — even if both processes are on the same machine. Such a performance effect cannot be ignored, even for believers in lazy optimization.
As a result any object that's intended to be used as a remote object needs a coarse-grained interface that minimizes the number of calls needed to get something done. Not only does this affect your method calls, it also affects your objects. Rather than ask for an order and its order lines individually, you need to access and update the order and order lines in a single call. This affects your entire object structure. You give up the clear intention and fine-grained control you get with small objects and small methods. Programming becomes more difficult and your productivity slows.
A Remote Facade is a coarse-grained facade (Gang of Four) over a web of fine-grained objects. None of the fine-grained objects have a remote interface, and the Remote Facade contains no domain logic. All the Remote Facade does is translate coarse-grained methods onto the underlying fine-grained objects.
Intent: An object that carries data between processes in order to reduce the number of method calls.
Source: catalog page · Chapter 15
classDiagram
class AlbumDTO {
title : String
artist : String
toXmlElement()
readXml()
}
class AlbumAssembler
class Album {
title : String
}
class Artist {
name : String
}
AlbumAssembler ..> AlbumDTO
AlbumAssembler ..> Album
AlbumAssembler ..> Artist
When you're working with a remote interface, such as Remote Facade, each call to it is expensive. As a result you need to reduce the number of calls, and that means that you need to transfer more data with each call. One way to do this is to use lots of parameters. However, this is often awkward to program — indeed, it's often impossible with languages such as Java that return only a single value.
The solution is to create a Data Transfer Object that can hold all the data for the call. It needs to be serializable to go across the connection. Usually an assembler is used on the server side to transfer data between the DTO and any domain objects.
Although the main reason for using a Data Transfer Object is to batch up what would be multiple remote calls into a single call, it's worth mentioning that another advantage is to encapsulate the serialization mechanism for transferring data over the wire. By encapsulating the serialization like this, the DTOs keep this logic out of the rest of the code and also provide a clear point to change serialization should you wish.
Note (2013-08-11): At the time I wrote this book the Sun/Java community used the term “value object” for data transfer objects. This caused considerable confusion since others used that term to mean a Value Object. Fortunately after a few years the Sun/Java community switched to using “Transfer Object” as the name for this pattern.
Intent: Prevents conflicts between concurrent business transactions by detecting a conflict and rolling back the transaction.
Source: catalog page · Chapter 16
Dashed boxes on the original sketch are system transaction boundaries; the long braces are business transaction boundaries.
sequenceDiagram
participant Martin as Martin's Session
participant DB as Database
participant David as David's Session
rect rgb(245,245,245)
Note over Martin,DB: system transaction
Martin->>DB: getCustomer 129
DB-->>Martin: return customer 129
end
Martin->>Martin: edit customer
rect rgb(245,245,245)
Note over DB,David: system transaction
David->>DB: getCustomer 129
DB-->>David: return customer 129
end
David->>David: edit customer
rect rgb(245,245,245)
Note over DB,David: system transaction
David->>DB: update customer 129
end
rect rgb(245,245,245)
Note over Martin,DB: system transaction
Martin->>DB: update customer 129
DB-->>Martin: failure: wrong customer version
end
Martin-->>Martin: rollback
Often a business transaction executes across a series of system transactions. Once outside the confines of a single system transaction, we can't depend on our database manager alone to ensure that the business transaction will leave the record data in a consistent state. Data integrity is at risk once two sessions begin to work on the same records and lost updates are quite possible. Also, with one session editing data that another is reading an inconsistent read becomes likely.
Optimistic Offline Lock solves this problem by validating that the changes about to be committed by one session don't conflict with the changes of another session. A successful pre-commit validation is, in a sense, obtaining a lock indicating it's okay to go ahead with the changes to the record data. So long as the validation and the updates occur within a single system transaction the business transaction will display consistency.
Whereas Pessimistic Offline Lock assumes that the chance of session conflict is high and therefore limits the system's concurrency, Optimistic Offline Lock assumes that the chance of conflict is low. The expectation that session conflict isn't likely allows multiple users to work with the same data at the same time.
Intent: Prevents conflicts between concurrent business transactions by allowing only one business transaction at a time to access data.
Source: catalog page · Chapter 16
sequenceDiagram
participant Martin as Martin's Session
participant DB as Database
participant David as David's Session
rect rgb(245,245,245)
Note over Martin,DB: system transaction
Martin->>DB: getCustomer(129)
DB-->>Martin: return customer 129
end
rect rgb(245,245,245)
Note over DB,David: system transaction
David->>DB: getCustomer(129)
DB-->>David: error: customer locked
end
Martin->>Martin: edit customer
Since offline concurrency involves manipulating data for a business transaction that spans multiple requests, the simplest approach would seem to be having a system transaction open for the whole business transaction. Sadly, however, this doesn't always work well because transaction systems aren't geared to work with long transactions. For that reason you have to use multiple system transactions, at which point you're left to your own devices to manage concurrent access to your data.
The first approach to try is Optimistic Offline Lock. However, that pattern has its problems. If several people access the same data within a business transaction, one of them will commit easily but the others will conflict and fail. Since the conflict is only detected at the end of the business transaction, the victims will do all the transaction work only to find at the last minute that the whole thing will fail and their time will have been wasted. If this happens a lot on lengthy business transactions the system will soon become very unpopular.
Pessimistic Offline Lock prevents conflicts by avoiding them altogether. It forces a business transaction to acquire a lock on a piece of data before it starts to use it, so that, most of the time, once you begin a business transaction you can be pretty sure you'll complete it without being bounced by concurrency control.
Intent: Locks a set of related objects with a single lock.
Source: catalog page · Chapter 16
classDiagram
class Customer
class Address
class Lock
Customer "1" *--> "*" Address
Lock "1" --> "1" Customer : locks aggregate
Objects can often be edited as a group. Perhaps you have a customer and its set of addresses. If so, when using the application it makes sense to lock all of these items if you want to lock any one of them. Having a separate lock for individual objects presents a number of challenges. First, anyone manipulating them has to write code that can find them all in order to lock them. This is easy enough for a customer and its addresses, but it gets tricky as you get more locking groups. And what if the groups get complicated? Where is this behavior when your framework is managing lock acquisition? If your locking strategy requires that an object be loaded in order to be locked, such as with Optimistic Offline Lock, locking a large group affects performance. And with Pessimistic Offline Lock a large lock set is a management headache and increases lock table contention.
A Coarse-Grained Lock is a single lock that covers many objects. It not only simplifies the locking action itself but also frees you from having to load all the members of a group in order to lock them.
Intent: Allows framework or layer supertype code to acquire offline locks.
Source: catalog page · Chapter 16
sequenceDiagram
participant BT as Business Transaction
participant FW as Framework
participant LM as Lock Manager
BT->>FW: load customer
FW->>LM: lock customer
LM-->>FW: success
FW-->>BT: return customer
The key to any locking scheme is that there are no gaps in its use. Forgetting to write a single line of code that acquires a lock can render an entire offline locking scheme useless. Failing to retrieve a read lock where other transactions use write locks means you might not get up-to-date session data; failing to use a version count properly can result in unknowingly writing over someone's changes. Generally, if an item might be locked anywhere it must be locked everywhere. Ignoring its application's locking strategy allows a business transaction to create inconsistent data. Not releasing locks won't corrupt your record data, but it will eventually bring productivity to a halt. Because offline concurrency management is difficult to test, such errors might go undetected by all of your test suites.
One solution is to not allow developers to make such a mistake. Locking tasks that cannot be overlooked should be handled not explicitly by developers but implicitly by the application. The fact that most enterprise applications make use of some combination of framework, Layer Supertypes, and code generation provides us with ample opportunity to facilitate Implicit Lock.
These three catalog pages have intent only (no sketch and no extra body text). The diagrams below are reconstructions of the idea, not copies of a catalog GIF.
Intent: Stores session state on the client.
Source: catalog page · Chapter 17
No catalog sketch. Reconstructed:
flowchart LR
C[Client\nsession data] -->|each request carries state| S[Server]
S -->|response may update state| C
Intent: Keeps the session state on a server system in a serialized form.
Source: catalog page · Chapter 17
No catalog sketch. Reconstructed:
flowchart LR
C[Client] -->|session id| S[Server]
S --> SS[(Serialized session store)]
Intent: Stores session data as committed data in the database.
Source: catalog page · Chapter 17
No catalog sketch. Reconstructed:
flowchart LR
C[Client] --> S[Server]
S --> DB[(Database\ncommitted session rows)]
Intent: An object that encapsulates access to an external system or resource.
Source: catalog page · Chapter 18 · later write-up: Gateway pattern (2021)
Domain objects depend on the gateway; the gateway depends on the external package:
flowchart LR
Customer --> PG[Pricing Gateway]
Lease --> PG
Asset --> PG
PG --> PP[Pricing Package]
Interesting software rarely lives in isolation. Even the purest object-oriented system often has to deal with things that aren't objects, such as relational database tables, CICS transactions, and XML data structures.
When accessing external resources like this, you'll usually get APIs for them. However, these APIs are naturally going to be somewhat complicated because they take the nature of the resource into account. Anyone who needs to understand a resource needs to understand its API — whether JDBC and SQL for relational databases or W3C or JDOM for XML. Not only does this make the software harder to understand, it also makes it much harder to change should you shift some data from a relational database to an XML message at some point in the future.
The answer is so common that it's hardly worth stating. Wrap all the special API code into a class whose interface looks like a regular object. Other objects access the resource through this Gateway, which translates the simple method calls into the appropriate specialized API.
In 2021 Fowler published a more detailed explanation of the Gateway pattern, which he says is better than the one in the book.
Intent: Removes dependence upon problematic services during testing.
Source: catalog page · Chapter 18
(The catalog intent line also includes the word “WSDL”, which is the stereotype on the remote service in the sketch.)
classDiagram
class ChargeGenerator
class TaxService {
<<interface>>
getTaxInfo()
}
class AcmeTaxService {
<<WSDL>>
getTaxInfo()
}
class TaxServiceStub {
<<class>>
getTaxInfo()
}
ChargeGenerator ..> TaxService
TaxService <|.. AcmeTaxService : over network
TaxService <|.. TaxServiceStub
Enterprise systems often depend on access to third-party services such as credit scoring, tax rate lookups, and pricing engines. Any developer who has built such a system can speak to the frustration of being dependent on resources completely out of his control. Feature delivery is unpredictable, and as these services are often remote reliability and performance can suffer as well.
At the very least these problems slow the development process. Developers sit around waiting for the service to come back on line or maybe put some hacks into the code to compensate for yet to be delivered features. Much worse, and quite likely, such dependencies will lead to times when tests can't execute. When tests can't run the development process is broken.
Replacing the service during testing with a Service Stub that runs locally, fast, and in memory improves your development experience.
Intent: An in-memory representation of tabular data.
Source: catalog page · Chapter 18
classDiagram
class RecordSet
class Table
class Row
class Column
RecordSet *--> "*" Table
Table *--> "*" Row
Table *--> "*" Column
In the last twenty years, the dominant way to represent data in a database has been the tabular relational form. Backed by database companies big and small, and a fairly standard query language, almost every new development I see uses relational data.
On top of this has come a wealth of tools for building UIs quickly. These data-aware UI frameworks rely on the fact that the underlying data is relational, and they provide UI widgets of various kinds that make it easy to view and manipulate this data with almost no programming.
The dark side of these environments is that, while they make display and simple updates ridiculously easy, they have no real facilities in which to place business logic. Any validations beyond “is this a valid date,” and any business rules or computations have no good place to go. Either they're jammed into the database as stored procedures or they're mingled with UI code.
The idea of the Record Set is to give you your cake and let you eat it, by providing an in-memory structure that looks exactly like the result of an SQL query but can be generated and manipulated by other parts of the system.
Intent: An object that sets up a communication between two independent objects.
Source: catalog page · Chapter 18
Unlike Gateway, the mapper points outward at both isolated sides so they stay ignorant of each other:
flowchart LR
Customer
Lease
Asset
PM[Pricing Mapper]
PP[Pricing Package]
PM -.-> Customer
PM -.-> Lease
PM -.-> Asset
PM -.-> PP
Sometimes you need to set up communications between two subsystems that still need to stay ignorant of each other. This may be because you can't modify them or you can but you don't want to create dependencies between the two or even between them and the isolating element.
Intent: A type that acts as the supertype for all types in its layer.
Source: catalog page · Chapter 18
No catalog sketch. Reconstructed:
classDiagram
class DomainObject {
id
load()
save()
}
class Customer
class Order
DomainObject <|-- Customer
DomainObject <|-- Order
It's not uncommon for all the objects in a layer to have methods you don't want to have duplicated throughout the system. You can move all of this behavior into a common Layer Supertype.
Intent: Defines an interface in a separate package from its implementation.
Source: catalog page · Chapter 18
classDiagram
class Customer
class Order
class UnitOfWork {
<<interface>>
}
class UnitOfWorkImpl
Customer ..> UnitOfWork
Order ..> UnitOfWork
UnitOfWork <|.. UnitOfWorkImpl
+---------------- domain ----------------+ +------ interfaces ------+
| Customer Order | | <<interface>> |
| | | | | Unit of Work |
| +-------------- uses ------------+--+-->| |
+-----------------------------------------+ +-----------^------------+
|
+---------------- data mapper ----------------------------+----------+
| Unit of Work Impl |
+--------------------------------------------------------------------+
As you develop a system, you can improve the quality of its design by reducing the coupling between the system's parts. A good way to do this is to group the classes into packages and control the dependencies between them. You can then follow rules about how classes in one package can call classes in another — for example, one that says that classes in the domain layer may not call classes in the presentation package.
However, you might need to invoke methods that contradict the general dependency structure. If so, use Separated Interface to define an interface in one package but implement it in another. This way a client that needs the dependency to the interface can be completely unaware of the implementation. The Separated Interface provides a good plug point for Gateway.
Intent: A well-known object that other objects can use to find common objects and services.
Source: catalog page · Chapter 18
classDiagram
class Registry {
getPerson(id)
addPerson(Person)
}
When you want to find an object you usually start with another object that has an association to it, and use the association to navigate to it. Thus, if you want to find all the orders for a customer, you start with the customer object and use a method on it to get the orders. However, in some cases you won't have an appropriate object to start with. You may know the customer's ID number but not have a reference. In this case you need some kind of lookup method — a finder — but the question remains: How do you get to the finder?
A Registry is essentially a global object, or at least it looks like one — even if it isn't as global as it may appear.
Intent: A small simple object, like money or a date range, whose equality isn't based on identity.
Source: catalog page · Chapter 18
No catalog sketch. Reconstructed:
classDiagram
class Money {
amount
currency
equals(other)
}
class DateRange {
start
end
equals(other)
}
With object systems of various kinds, I've found it useful to distinguish between reference objects and Value Objects. Of the two a Value Object is usually the smaller; it's similar to the primitive types present in many languages that aren't purely object-oriented.
Intent: Represents a monetary value.
Source: catalog page · Chapter 18
classDiagram
class Money {
amount
currency
allocate()
}
A large proportion of the computers in this world manipulate money, so it's always puzzled me that money isn't actually a first class data type in any mainstream programming language. The lack of a type causes problems, the most obvious surrounding currencies. If all your calculations are done in a single currency, this isn't a huge problem, but once you involve multiple currencies you want to avoid adding your dollars to your yen without taking the currency differences into account. The more subtle problem is with rounding. Monetary calculations are often rounded to the smallest currency unit. When you do this it's easy to lose pennies (or your local equivalent) because of rounding errors.
The good thing about object-oriented programming is that you can fix these problems by creating a Money class that handles them. Of course, it's still surprising that none of the mainstream base class libraries actually do this.
Intent: A subclass that provides special behavior for particular cases.
Source: catalog page · Chapter 18
classDiagram
class Customer
class MissingCustomer
class UnknownCustomer
Customer <|-- MissingCustomer
Customer <|-- UnknownCustomer
Nulls are awkward things in object-oriented programs because they defeat polymorphism. Usually you can invoke foo freely on a variable reference of a given type without worrying about whether the item is the exact type or a subclass. With a strongly typed language you can even have the compiler check that the call is correct. However, since a variable can contain null, you may run into a runtime error by invoking a message on null, which will get you a nice, friendly stack trace.
If it's possible for a variable to be null, you have to remember to surround it with null test code so you'll do the right thing if a null is present. Often the right thing is same in many contexts, so you end up writing similar code in lots of places — committing the sin of code duplication.
Nulls are a common example of such problems and others crop up regularly. In number systems you have to deal with infinity, which has special rules for things like addition that break the usual invariants of real numbers. One of my earliest experiences in business software was with a utility customer who wasn't fully known, referred to as “occupant.” All of these imply altering the usual behavior of the type.
Instead of returning null, or some odd value, return a Special Case that has the same interface as what the caller expects.
Intent: Links classes during configuration rather than compilation.
Source: catalog page · Chapter 18
classDiagram
class DomainObject {
id : Long
}
class IdGenerator {
<<interface>>
}
DomainObject --> IdGenerator
Separated Interface is often used when application code runs in multiple runtime environments, each requiring different implementations of particular behavior. Most developers supply the correct implementation by writing a factory method. Suppose you define your primary key generator with a Separated Interface so that you can use a simple in-memory counter for unit testing but a database-managed sequence for production. Your factory method will most likely contain a conditional statement that looks at a local environment variable, determines if the system is in test mode, and returns the correct key generator. Once you have a few factories you have a mess on your hands. Establishing a new deployment configuration — say “execute unit tests against in-memory database without transaction control” or “execute in production mode against DB2 database with full transaction control” — requires editing conditional statements in a number of factories, rebuilding, and redeploying. Configuration shouldn't be scattered throughout your application, nor should it require a rebuild or redeployment. Plugin solves both problems by providing centralized, runtime configuration.