Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

 

1. Introduction

In this article, we’re going to focus on Structural Design Patterns in Java – and discuss what these are and some fundamental differences between some of them.

2. Structural Design Patterns

According to the Gang Of Four (GoF), design patterns can be classified into three types:

  1. Creational
  2. Structural
  3. Behavioral

Simply put, Structural Patterns deal with the composition of classes and objects. They provide different ways of using object composition and inheritance to create some abstraction.

3. Proxy Pattern

With this pattern, we create an intermediary that acts as an interface to another resource, e.g., a file, a connection. This secondary access provides a surrogate for the real component and protects it from the underlying complexity.

For a detailed example of the pattern, have a look at the dedicated post: The Proxy Pattern in Java.

Key Points of Differentiation:

  • The proxy provides the same interface as the object it’s holding the reference to, and it doesn’t modify the data in any manner; it’s in contrast to Adapter and Decorator patterns which alter and decorate the functionalities of pre-existing instances respectively
  • The Proxy usually has the information about the real subject at the compile time itself whereas Decorator and Adapter get injected at runtime, knowing only the actual object’s interface

4. Decorator Pattern

This pattern is useful for enhancing the behavior of an object. For a detailed overview, have a look at the focused tutorial here: Decorator Pattern in Java

Key points of differentiation:

  • Although Proxy and Decorator patterns have similar structures, they differ in intention; while Proxy’s prime purpose is to facilitate ease of use or controlled access, a Decorator attaches additional responsibilities
  • Both Proxy and Adapter patterns hold a reference to the original object
  • All the decorators from this pattern can be used recursively, an infinite number of times, which is not possible with other models

5. Adapter Pattern

The Adapter pattern is used for connecting two incompatible interfaces that otherwise cannot be connected directly. An Adapter wraps an existing class with a new interface so that it becomes compatible with the interface needed.

For a detailed description and implementation, have a look at the dedicated post: Adapter Pattern in Java

The main differences between Adapter and Proxy patterns are:

  • While proxy provides the same interface, Adapter provides a different interface that’s compatible with its client
  • Adapter pattern is used after the application components are designed so that we can use them without modifying the source code. This is in contrast to the Bridge pattern, which is used before the components are designed.

6. Bridge Pattern

The official definition for Bridge design pattern introduced by Gang of Four (GoF) is to decouple an abstraction from its implementation so that the two can vary independently.

This means to create a bridge interface that uses OOP principles to separate out responsibilities into different abstract classes.

6.1. Bridge Pattern Example

For the Bridge pattern, we’ll consider two layers of abstraction; one is the geometric shape (like triangle and square) which is filled with different colors (our second abstraction layer):

First, we’ll define a color interface:

public interface Color {
    String fill();
}

Now we’ll create a concrete class for this interface:

public class Blue implements Color {
    @Override
    public String fill() {
        return "Color is Blue";
    }
}

Let’s now create an abstract Shape class which consists a reference (bridge) to the Color object:

public abstract class Shape {
    protected Color color;
    
    //standard constructors
    
    abstract public String draw();
}

We’ll now create a concrete class of Shape interface which will utilize method from Color interface as well:

public class Square extends Shape {

    public Square(Color color) {
        super(color);
    }

    @Override
    public String draw() {
        return "Square drawn. " + color.fill();
    }
}

For this pattern, the following assertion will be true:

@Test
public void whenBridgePatternInvoked_thenConfigSuccess() {
    //a square with red color
    Shape square = new Square(new Red());
 
    assertEquals(square.draw(), "Square drawn. Color is Red");
}

Here, we’re using Bridge pattern and passing the desired color object. As we can note in the output, the shape gets draws with the desired color:

Square drawn. Color: Red
Triangle drawn. Color: Blue

6.2. When to Use Bridge Design Pattern

  • When we want a parent abstract class to define the set of basic rules, and the concrete classes to add additional rules
  • When we have an abstract class that has a reference to the objects, and it has abstract methods that will be defined in each of the concrete classes

6.3. Key Points of Differentiation

  • A Bridge pattern can only be implemented before the application is designed.
  • Allows an abstraction and implementation to change independently whereas an Adapter pattern makes it possible for incompatible classes to work together

7. Conclusion

In this article, we focused on the Structural Design Pattern and differences between some of its types.

As always, the full implementation of this tutorial can be found over on Github.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE