Home About Me

Design Patterns Hiding in Plain Sight in the JDK

The JDK is usually treated as a standard library, but it is also a long accumulation of design choices. Classic patterns appear in its APIs so often that they can be easy to miss. Grouping a few examples by pattern category makes the connection between the vocabulary and the code more concrete.

Structural patterns

Adapter

Changes one interface or class into another shape.

  • java.util.Arrays#asList()
  • javax.swing.JTable(TableModel)
  • java.io.InputStreamReader(InputStream)
  • java.io.OutputStreamWriter(OutputStream)
  • javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
  • javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()

Bridge

Separates abstraction from implementation so that both can vary independently.

  • AWT (an abstraction layer mapped onto the native operating system)
  • JDBC

Composite

Lets callers treat individual objects and composed objects uniformly.

  • javax.swing.JComponent#add(Component)
  • java.awt.Container#add(Component)
  • java.util.Map#putAll(Map)
  • java.util.List#addAll(Collection)
  • java.util.Set#addAll(Collection)

Decorator

Adds a series of behaviors to an object dynamically, avoiding a large inheritance tree for every combination. It is hard to avoid in the JDK; the list below is only a sample.

  • java.io.BufferedInputStream(InputStream)
  • java.io.DataInputStream(InputStream)
  • java.io.BufferedOutputStream(OutputStream)
  • java.util.zip.ZipOutputStream(OutputStream)
  • java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()

Facade

Wraps a set of components, interfaces, abstractions, or subsystems behind a simpler interface.

  • java.lang.Class
  • javax.faces.webapp.FacesServlet

Flyweight

Stores many small objects efficiently.

  • java.lang.Integer#valueOf(int)
  • java.lang.Boolean#valueOf(boolean)
  • java.lang.Byte#valueOf(byte)
  • java.lang.Character#valueOf(char)

Proxy

Uses a simple object in place of a more complex one.

  • java.lang.reflect.Proxy
  • RMI

Creational patterns

Abstract factory

Creates families of related object instances. It is common in the JDK and in frameworks such as Spring, so examples are not hard to find.

  • java.util.Calendar#getInstance()
  • java.util.Arrays#asList()
  • java.util.ResourceBundle#getBundle()
  • java.sql.DriverManager#getConnection()
  • java.sql.Connection#createStatement()
  • java.sql.Statement#executeQuery()
  • java.text.NumberFormat#getInstance()
  • javax.xml.transform.TransformerFactory#newInstance()

Builder

Mainly simplifies construction of a complex object. It can also support a fluent interface.

  • java.lang.StringBuilder#append()
  • java.lang.StringBuffer#append()
  • java.sql.PreparedStatement
  • javax.swing.GroupLayout.Group#addComponent()

Factory

Returns an instance of a type according to demand, in the simplest sense.

  • java.lang.Proxy#newProxyInstance()
  • java.lang.Object#toString()
  • java.lang.Class#newInstance()
  • java.lang.reflect.Array#newInstance()
  • java.lang.reflect.Constructor#newInstance()
  • java.lang.Boolean#valueOf(String)
  • java.lang.Class#forName()

Prototype

Creates a new instance from an existing instance. Sometimes constructing an object and copying values from an existing one is a complicated operation; this pattern avoids that complexity.

  • java.lang.Object#clone()
  • java.lang.Cloneable

Singleton

Allows only one instance. Effective Java recommends an enum for this.

  • java.lang.Runtime#getRuntime()
  • java.awt.Toolkit#getDefaultToolkit()
  • java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
  • java.awt.Desktop#getDesktop()

Behavioral patterns

Chain of responsibility

Passes an object along a chain until some link handles it. Every object in the chain shares the same interface or abstract class but has a different implementation.

  • java.util.logging.Logger#log()
  • javax.servlet.Filter#doFilter()

Command

Encapsulates one or more commands in an object.

  • java.lang.Runnable
  • javax.swing.Action

Interpreter

A pattern for a grammar interpreter.

  • java.util.Pattern
  • java.text.Normalizer
  • java.text.Format

Iterator

Provides a consistent way to traverse all elements in a container in order.

  • java.util.Iterator
  • java.util.Enumeration

Mediator

Reduces direct communication dependencies between objects. A middle class manages the direction of messages.

  • java.util.Timer
  • java.util.concurrent.Executor#execute()
  • java.util.concurrent.ExecutorService#submit()
  • java.lang.reflect.Method#invoke()

Memento

Takes a snapshot of an object's state. Date uses a long internally for this snapshot.

  • java.util.Date
  • java.io.Serializable

Null Object

Handles the case where a collection has no elements.

  • java.util.Collections#emptyList()
  • java.util.Collections#emptyMap()
  • java.util.Collections#emptySet()

Observer

Lets an object broadcast its messages or events to all listening objects.

  • java.util.EventListener
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.faces.event.PhaseListener

State

Lets an object change behavior at runtime according to its internal state.

  • java.util.Iterator
  • javax.faces.lifecycle.LifeCycle#execute()

Strategy

Defines a family of algorithms, encapsulates each one in an object, and allows one to be selected flexibly at runtime.

  • java.util.Comparator#compare()
  • javax.servlet.http.HttpServlet
  • javax.servlet.Filter#doFilter()

Template method

Lets subclasses override part of a parent class without rewriting all of it.

  • java.util.Collections#sort()
  • java.io.InputStream#skip()
  • java.io.InputStream#read()
  • java.util.AbstractList#indexOf()

Visitor

Represents an operation over objects in an object group. It lets you define new operations on those objects without changing the objects themselves.

  • javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
  • javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor