by BehindJava

What are the examples of GoF Design Patterns in Java's core libraries

Home » java » What are the examples of GoF Design Patterns in Java's core libraries

In this tutorial we are going to learn about GoF Design Patterns and its real time examples in Java core libraries.

Design Patterns

Design patterns, as name suggest, are solutions for most commonly (and frequently) occurred problems while designing a software. These patterns are mostly “evolved” rather than “discovered”. A lot of learning, by lots of professional, have been summarized into these design patterns. None of these patterns force you anything in regard to implementation; they are just guidelines to solve a particular problem – in a particular way – in particular contexts. Code implementation is your responsibility.

We have 3 Major Design Patterns i.e.,

  1. Creational Design Patterns
  2. Structural Design Patterns
  3. Behavioral Design Patterns

Creational Design Patterns

Creational patterns often used in place of direct instantiation with constructors. They make the creation process more adaptable and dynamic. In particular, they can provide a great deal of flexibility about which objects are created, how those objects are created, and how they are initialized.

1. Abstract factory: Abstract factory pattern is used whenever we need another level of abstraction over a group of factories created using factory pattern. (recognizeable by creational methods returning the factory itself which in turn can be used to create another abstract/interface type).

Real time examples:

  • javax.xml.parsers.DocumentBuilderFactory#newInstance().
  • javax.xml.transform.TransformerFactory#newInstance().
  • javax.xml.xpath.XPathFactory#newInstance().

2. Builder: Builder design pattern is an alternative way to construct complex objects and should be used only when we want to build different types of immutable objects using same object building process.(recognizeable by creational methods returning the instance itself).

Real time examples:

  • java.lang.StringBuilder#append() (unsynchronized)
  • java.lang.StringBuffer#append() (synchronized)
  • java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
  • javax.swing.GroupLayout.Group#addComponent()
  • All implementations of java.lang.Appendable
  • java.util.stream.Stream.Builder

3. Factory: Factory design pattern is most suitable when complex object creation steps are involved. To ensure that these steps are centralized and not exposed to composing classes. (recognizeable by creational methods returning an implementation of an abstract/interface type).

Real time examples:

  • java.util.Calendar#getInstance()
  • java.util.ResourceBundle#getBundle()
  • java.text.NumberFormat#getInstance()
  • java.nio.charset.Charset#forName()
  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Returns singleton object per protocol)
  • java.util.EnumSet#of()
  • javax.xml.bind.JAXBContext#createMarshaller() and other similar methods

4. Prototype: Prototype design pattern is used in scenarios where application needs to create a large number of instances of a class, which have almost same state or differ very little. (recognizeable by creational methods returning a different instance of itself with the same properties).

Real time examples:

  • java.lang.Object#clone() (the class has to implement java.lang.Cloneable)

5. Singleton: Singleton enables an application to have one and only one instance of a class per JVM.(recognizeable by creational methods returning the same instance (usually of itself) everytime).

Real time examples:

  • java.lang.Runtime#getRuntime()
  • java.awt.Desktop#getDesktop()
  • java.lang.System#getSecurityManager()

Structural Design Patterns

Structural design patterns show us how to glue different pieces of a system together in a flexible and extensible fashion. These patterns help us guarantee that when one of the parts changes, the entire application structure does not need to change.

1. Adapter: An adapter convert the interface of a class into another interface clients expect. It lets classes work together that couldn’t otherwise because of incompatible interfaces. (recognizeable by creational methods taking an instance of different abstract/interface type and returning an implementation of own/another abstract/interface type which decorates/overrides the given instance).

Real time examples:

  • java.util.Arrays#asList()
  • java.util.Collections#list()
  • java.util.Collections#enumeration()
  • java.io.InputStreamReader(InputStream) (returns a Reader)
  • java.io.OutputStreamWriter(OutputStream) (returns a Writer)
  • javax.xml.bind.annotation.adapters.XmlAdapter#marshal() and #unmarshal()

2. Bridge: Bridge design pattern is used to decouple a class into two parts – abstraction and it’s implementation – so that both can evolve in future without affecting each other. It increases the loose coupling between class abstraction and it’s implementation. (recognizeable by creational methods taking an instance of different abstract/interface type and returning an implementation of own abstract/interface type which delegates/uses the given instance)

Real time examples:

  • None comes to mind yet. A fictive example would be new LinkedHashMap(LinkedHashSet, List) which returns an unmodifiable linked map which doesn’t clone the items, but uses them. The java.util.Collections#newSetFromMap() and singletonXXX() methods however comes close.

3. Composite: Composite design pattern helps to compose the objects into tree structures to represent whole-part hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. (recognizeable by behavioral methods taking an instance of same abstract/interface type into a tree structure).

Real time examples:

  • java.awt.Container#add(Component) (practically all over Swing thus)
  • javax.faces.component.UIComponent#getChildren() (practically all over JSF UI thus)

4. Decorator: Decorator design pattern is used to add additional features or behaviors to a particular instance of a class, while not modifying the other instances of same class. (recognizeable by creational methods taking an instance of same abstract/interface type which adds additional behaviour).

Real time examples:

  • All subclasses of java.io.InputStream, OutputStream, Reader and Writer have a constructor taking an instance of same type.
  • java.util.Collections, the checkedXXX(), synchronizedXXX() and unmodifiableXXX() methods.
  • javax.servlet.http.HttpServletRequestWrapper and HttpServletResponseWrapper
  • javax.swing.JScrollPane

5. Facade: Facade design pattern provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. (recognizeable by behavioral methods which internally uses instances of different independent abstract/interface types).

Real time examples:

  • javax.faces.context.FacesContext, it internally uses among others the abstract/interface types LifeCycle, ViewHandler, NavigationHandler and many more without that the enduser has to worry about it (which are however overrideable by injection).
  • javax.faces.context.ExternalContext, which internally uses ServletContext, HttpSession, HttpServletRequest, HttpServletResponse, etc.

6. Flyweight: Flyweight design pattern enables use sharing of objects to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context.(recognizeable by creational methods returning a cached instance, a bit the “multiton” idea).

Real time examples:

  • java.lang.Integer#valueOf(int) (also on Boolean, Byte, Character, Short, Long and BigDecimal)

7. Proxy: In proxy design pattern, a proxy object provide a surrogate or placeholder for another object to control access to it. Proxy is heavily used to implement lazy loading related usecases where we do not want to create full object until it is actually needed. (recognizeable by creational methods which returns an implementation of given abstract/interface type which in turn delegates/uses a different implementation of given abstract/interface type).

Real time examples:

  • java.lang.reflect.Proxy
  • java.rmi.*
  • javax.ejb.EJB (explanation here)
  • javax.inject.Inject (explanation here)
  • javax.persistence.PersistenceContext

Behavioral Design Patterns

Behavioral patterns abstract an action we want to take on the object or class that takes the action. By changing the object or class, we can change the algorithm used, the objects affected, or the behavior, while still retaining the same basic interface for client classes.

1. Chain of responsibility: Chain of responsibility design pattern gives more than one object an opportunity to handle a request by linking receiving objects together in form of a chain. (recognizeable by behavioral methods which (indirectly) invokes the same method in another implementation of same abstract/interface type in a queue).

Real time examples:

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

2. Command: Command design pattern is useful to abstract the business logic into discrete actions which we call commands. These command objects help in loose coupling between two classes where one class (invoker) shall call a method on other class (receiver) to perform a business operation.(recognizeable by behavioral methods in an abstract/interface type which invokes a method in an implementation of a different abstract/interface type which has been encapsulated by the command implementation during its creation).

Real time examples:

  • All implementations of java.lang.Runnable
  • All implementations of javax.swing.Action

3. Interpreter: Interpreter pattern specifies how to evaluate sentences in a language, programatically. It helps in building a grammar for a simple language, so that sentences in the language can be interpreted.(recognizeable by behavioral methods returning a structurally different instance/type of the given instance/type; note that parsing/formatting is not part of the pattern, determining the pattern and how to apply it is).

Real time examples:

  • java.util.Pattern *java.text.Normalizer
  • All subclasses of java.text.Format
  • All subclasses of javax.el.ELResolver

4. Iterator: Iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(recognizeable by behavioral methods sequentially returning instances of a different type from a queue).

Real time examples:

  • All implementations of java.util.Iterator (thus among others also java.util.Scanner!).
  • All implementations of java.util.Enumeration

5. Mediator: Mediator pattern defines 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 us vary their interaction independently.(recognizeable by behavioral methods taking an instance of different abstract/interface type (usually using the command pattern) which delegates/uses the given instance).

Real time examples:

  • java.util.Timer (all scheduleXXX() methods)
  • java.util.concurrent.Executor#execute()
  • java.util.concurrent.ExecutorService (the invokeXXX() and submit() methods)
  • java.util.concurrent.ScheduledExecutorService (all scheduleXXX() methods)
  • java.lang.reflect.Method#invoke()

6. Memento: Memento pattern is used to restore state of an object to a previous state. It is also known as snapshot pattern.(recognizeable by behavioral methods which internally changes the state of the whole instance).

Real time examples:

  • java.util.Date (the setter methods do that, Date is internally represented by a long value)
  • All implementations of java.io.Serializable
  • All implementations of javax.faces.component.StateHolder

7. Observer: Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. It is also referred to as the publish-subscribe pattern.(or Publish/Subscribe) (recognizeable by behavioral methods which invokes a method on an instance of another abstract/interface type, depending on own state).

Real time examples:

  • java.util.Observer/java.util.Observable (rarely used in real world though)
  • All implementations of java.util.EventListener (practically all over Swing thus)
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.faces.event.PhaseListener

8. State: In state pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. There shall be a separate concrete class per possible state of an object.(recognizeable by behavioral methods which changes its behaviour depending on the instance’s state which can be controlled externally).

Real time examples:

  • javax.faces.lifecycle.LifeCycle#execute() (controlled by FacesServlet, the behaviour is dependent on current phase (state) of JSF lifecycle)

9. Strategy: Strategy pattern is used where we choose a specific implementation of algorithm or task in run time – out of multiple other implementations for same task.(recognizeable by behavioral methods in an abstract/interface type which invokes a method in an implementation of a different abstract/interface type which has been passed-in as method argument into the strategy implementation).

Real time examples:

  • java.util.Comparator#compare(), executed by among others Collections#sort().
  • javax.servlet.http.HttpServlet, the service() and all doXXX() methods take HttpServletRequest and HttpServletResponse and the implementor has to process them (and not to get hold of them as instance variables!).
  • javax.servlet.Filter#doFilter()

10. Template method: Template method pattern defines the sequential steps to execute a multi-step algorithm and optionally can provide a default implementation as well (based on requirements).(recognizeable by behavioral methods which already have a “default” behaviour efined by an abstract type).

Real time examples:

  • All non-abstract methods of java.io.InputStream, java.io.OutputStream, java.io.Reader and java.io.Writer.
  • All non-abstract methods of java.util.AbstractList, java.util.AbstractSet and java.util.AbstractMap.
  • javax.servlet.http.HttpServlet, all the doXXX() methods by default sends a HTTP 405 “Method Not Allowed” error to the response. You’re free to implement none or any of them.

11. Visitor: Visitor pattern is used when we want a hierarchy of objects to modify their behavior but without modifying their source code.(recognizeable by two different abstract/interface types which has methods defined which takes each the other abstract/interface type; the one actually calls the method of the other and the other executes the desired strategy on it).

Real time examples:

  • javax.lang.model.element.AnnotationValue and AnnotationValueVisitor
  • javax.lang.model.element.Element and ElementVisitor
  • javax.lang.model.type.TypeMirror and TypeVisitor
  • java.nio.file.FileVisitor and SimpleFileVisitor
  • javax.faces.component.visit.VisitContext and VisitCallback