Java Design Patterns: Proven Solutions to Common Problems

Java Design Patterns: Proven Solutions to Common Problems

Design patterns have two major benefits. First, they provide proven solutions to common development issues. Each solution facilitates the development of highly cohesive modules with minimal coupling. Design patterns make the overall system easier to understand and maintain. Second, they make communication between developers and designers more efficient.

In general, patterns have four essential elements.

The pattern name is a handle developers can use to describe — in a word or two — a design problem, its consequences and its solutions. Naming a pattern immediately increases developers’ design vocabulary, allowing them to design at a higher level of abstraction. Having a vocabulary for patterns also makes it easier to think about designs and to communicate them and their trade-offs to others. However, finding good names is one of the hardest parts of developing the design pattern catalog.

The problem defines the design problem and its context, and describes when to apply the pattern to it. It might describe specific design problems such as how to represent algorithms as objects. It might describe class or object structures that are symptomatic of an inflexible design. Sometimes the problem will include a list of conditions that must be met before it makes sense to apply the pattern.

The solution defines the elements that make up the design: their relationships, responsibilities, and collaborations. The solution doesn’t describe a particular concrete design or implementation, because a pattern is like a template that can be applied in many different situations. Instead, the pattern provides an abstract description of a design problem and how a general arrangement of elements (classes and objects in this case) solves it.

The consequences are the results and trade-offs of applying the pattern. Though consequences are often unvoiced when developers describe design decisions, they are critical for evaluating design alternatives and for understanding the costs and benefits of applying the pattern. The consequences for software often concern space and time trade-offs. They may address language and implementation issues as well. Because reuse is often a factor in object-oriented design, the consequences of a pattern include its impact on a system’s flexibility, extensibility, or portability. Listing these consequences explicitly helps you understand and evaluate them.

Table 1 lists the names and descriptions of a general design pattern template.

Pattern name and classificationA conceptual handle and category for the pattern
IntentWhat problem does the pattern address?
Also known asOther common names for the pattern
MotivationA scenario that illustrates the problem
ApplicabilityIn what situation can the pattern be used?
StructureDiagram using the Object Modeling Technique (OMT)
ParticipantsClass and objects in design
CollaborationsHow classes and objects in the design collaborate
ConsequencesWhat objectives does the pattern achieve? What are the tradeoffs?
ImplementationImplementation details to consider, language-specific issues
Sample codeSample code in Java and C++
Known usesExamples from the real world
Related patternsComparison and discussion of related patterns
Table 1. General Design Pattern Template Name and Description

Table 2 lists the names and descriptions of a Java-specific design pattern template.

Pattern nameThe name and a reference to where it was first described
SynopsisA very short description of the pattern
ContextA description of the problem the pattern is intended to solve
ForcesA description of the considerations that led to the solution
SolutionA description of the general solution
ConsequencesImplications of using the pattern
ImplementationImplementation details to consider
Java API usageAn example from the Java APO (when available)
Code exampleA code example in the Java language
Related patternsA list of related patterns
Table 2. Java Design Pattern Template Name and Description

The Structure of Java Design Patterns

Design patterns vary in their level of abstraction. There are many design patterns, so it helps to organize them. The sections to follow classify design patterns so that developers can refer to the appropriate patterns. Through this classification, it’s easy to identify as well as incorporate new patterns.

In 1995, software professionals Eric Gamma, Richard Helm, Ralph Johnson and John Vlissides (also known as the Gang of Four or simply GoF) published a book titled Design Patterns. This book is considered the bible or “Gita” of design patterns to the software community at large and it has been very influential in the evolution of design patterns.

Design Patterns described 23 patterns based on the experience of the authors at that time. Today, some 250 or more design patterns are used in the object-oriented world. To organize them, the GoF established three design pattern categories:

  • Creational patterns
  • Structural patterns
  • Behavioral patterns

A creational pattern prescribes the way that objects are created. These patterns are used when a decision must be made at the time a class is instantiated. Typically, the details of the classes that are instantiated — what exactly they are, how and when they are created, and so on — are encapsulated by an abstract superclass and hidden from the client class, which knows only about the abstract class or the interface it implements. The specific type of the concrete class is typically unknown to the client class.

Structural patterns prescribe the organization of classes and objects. These patterns are concerned with how classes inherit from each other or how they are composed from other classes. Common structure patterns include adaptor, proxy and decorator patterns. These patterns are similar in that they introduce a level of indirection between a client class and the class it wants to use. Their intents are different, however.

The adaptor patterns uses indirection to modify the interface of a class to make it easier for a client class to use. The decorator pattern uses indirection to add behavior to a class, without unduly affecting the client class. The proxy pattern uses indirection to transparently provide a stand-in for another class.

Behavioral patterns prescribe the way objects interact with each other. They help make complex behavior manageable by specifying the responsibilities of objects and the ways they communicate with each other.

I further categorize design patterns using two criteria: Scope and Purpose. Scope specifies whether a pattern applies primarily to a class or its objects. Class patterns deal with the relationship between classes and their subclasses. Relationships are initiated through inheritance, so they are fixed at compile time. Objects deal with object relationships, which can change at run time. Almost all patterns use inheritance, so those patterns focus on pure class patterns — patterns I labeled under class.

Purpose explains what a pattern does. Creational patterns concern the process of object creation. Structural patterns deal with the composition of classes or objects. Behavioral patterns characterize the way in which a class or object interacts and is distributed. See Figure 1 for a table of design pattern structures.

Source: Design Patterns: Elements of Reusable Object-Oriented Software

There are other ways to organize patterns. Some patterns result in similar designs even though they have different intents. You can also pass reference to other patterns to meet your requirements. Figure 2 shows design patterns’ relationship with each other.

Source: Design Patterns: Elements of Reusable Object-Oriented Software

How Design Patterns Solve Your Problems

Design patterns exist to capture best practices and propagate solutions to commonly recurring problems. The solution lies in establishing the structure and responsibilities of the individual classes and objects that make up the pattern. The main point, however, is that patterns help to identify and isolate system-level variability so the software can evolve over time without adversely affecting the underlying design structure.

The fundamental goals of creating good object-oriented designs are:

  • Encapsulate system variability
  • Favor composition over inheritance
  • Design an interface

How to Select the Right Design Pattern

When a developer decides to use a design pattern to overcome an existing issue, he or she has to choose the kind of design pattern that will fulfill this requirement. The first step is to identify which type of design pattern — creational, structural or behavioral — is going to work well for the problem?

  • If you are trying to separate the process of object construction then use creational design patterns such as the singleton, factory, abstract factory and builder patterns.
  • If you are trying to interface to a sub-system, connect to an interface your system doesn’t support, or provide a flexible storage structure for adding and manipulating objects, then use structural design patterns such as the bridge, composite and façade patterns.
  • If you are trying to access objects, perform operations or interact with operations, use behavioral patterns such as the command, iterator, observer, strategy and visitor patterns.

Now that you have determined which category your problem exists in and you have identified the principle problem you are trying to address, you can begin searching for a pattern that is designed to match your intention.

If you have articulated your intention correctly and cannot find a pattern to match, don’t fret. A design pattern may not be your solution. Design patterns address problems that occur over and over again so that the solutions they offer can be replicated. Your problem may not occur over repeatedly and thus does not have a repeatable solution.

In three upcoming articles, I will go through each design pattern category in detail, including definition, benefits, usability and examples.

Stay tuned.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist