Monday, January 8, 2024

Structural patterns

1. Adapter Pattern

2. Composite Pattern

3. Proxy Pattern

4. Flyweight Pattern

5. Façade Pattern

6. Bridge Pattern

7. Decorator Pattern


Adapter design pattern:

Adapter design pattern is one of the structural design patterns that makes two unrelated interfaces work together. Moreover, the object that joins these unrelated interfaces is called an Adapter just like a mediator. As a real-life example, we can think of a mobile charger as an adapter because mobile battery needs 3 volts to charge, but the normal socket produces either 120V (in US) or 240V (in India). Therefore, the mobile charger works as an adapter between mobile charging socket and the wall socket.

In the adapter pattern, a wrapper class (i.e., the adapter) is used to translate requests from it to another class (i.e., the adoptee). In effect, an adapter provides particular interactions with an adoptee that are not offered directly by the adoptee.

When to use Adapter Pattern

The Adapter pattern should be used when:

  1. There is an existing class, and its interface does not match the one you need.
  2. You want to create a reusable class that co-operates with unrelated or unforeseen classes, that is, classes that don’t necessarily have compatible interfaces.
  3. There are several existing subclasses to be used, but it’s impractical to adapt their interface by sub-classing each one. An object adapter can adapt the interface of its parent class.

Adapter Pattern Example in JDK

  • util.Arrays#asList()
  • io.InputStreamReader(InputStream) (returns a Reader)
  • io.OutputStreamWriter(OutputStream) (returns a Writer)


Composite Design Pattern

The Composite Pattern allows you to compose objects into a tree structure to represent the part-whole hierarchy. It means you can create a tree of objects that is made of different parts, but that can be treated as a whole one big thing. Composite lets clients treat individual objects and compositions of objects uniformly, that’s the intent of the Composite Pattern.

In the composite pattern, a tree structure exists where identical operations can be performed on leaves and nodes. A node in a tree is a class that can have children. A node class is a ‘composite’ class. A leaf in a tree is a ‘primitive’ class that does not have children. The children of a composite can be leaves or other composites.

When to use Composite Pattern

Below is the conditions when we can use this pattern:

  1. When we want to represent part-whole hierarchies of objects.
  2. When we want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly.

Usage in JDK

java.awt.Container#add (Component) is a great example of Composite pattern in java and used a lot in Swing.


Proxy Design Pattern

The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. In fact, the Proxy Pattern is used to create a representative object that controls access to another object. It may be remote, expensive to create or in need of being secured.

In the Proxy Design Pattern, a client does not directly talk to the original object, it delegates calls to the proxy object which calls the methods of the original object. Moreover, the important point is that the client does not know about the proxy.

When to use the Proxy Pattern

Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to an object than a simple pointer. Here are several common situations in which the Proxy pattern is applicable:

  1. A remote proxy provides a local representative for an object in a different address space.
  2. A virtual proxy creates expensive objects on demand.
  3. A protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights.

Proxy Pattern in JDK

The following cases are examples of usage of the Proxy Pattern in the JDK.

  1. lang.reflect.Proxy
  2. rmi.* (whole package)


Flyweight Design Pattern

In the flyweight pattern, instead of creating large numbers of similar objects, we re-use objects. We can use it to reduce memory requirements and instantiation time and related costs.

Before we apply the flyweight design pattern, we need to consider the following factors:

  • If the number of Objects required in the application are huge in amount.
  • Also, if the object creation is heavy on memory and it can also be time consuming.

When to Use

Flyweight design pattern facilitates us when we need to create a lot of Objects of a class. Since every object consumes memory space, it can play a crucial role for low memory devices, such as mobile devices or embedded systems. Moreover, we can apply flyweight design pattern in order to reduce the load on memory with the help of object’s sharing.

Flyweight Pattern Example in JDK

All the wrapper classes valueOf () method uses cached objects showing use of Flyweight design pattern. The best example is Java String class String Pool implementation.


Facade Design Pattern

The Facade Design Pattern is a structural design pattern. In the facade pattern, facade classes are used to provide a single interface to set of classes. The facade simplifies a client’s interaction with a complex system by localizing the interactions into a single interface. As a result, the client can interact with a single object rather than being required to interact directly in complicated ways with the objects that make up the subsystem.

According to GoF: ‘Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use’.

When to use 

  • Facade pattern is more like a helper for client applications; it doesn’t hide subsystem interfaces from the client. Whether to use Facade or not is completely dependent on client code.
  • Facade pattern can be applied at any point of development, usually when the number of interfaces grows and system gets complex.
  • Subsystem interfaces are not aware of Facade and they shouldn’t have any reference of the Facade interface.
  • A facade pattern should be applied for similar kind of interfaces; its purpose is to provide a single interface rather than multiple interfaces that does the similar kind of jobs.
  • The subsystem may be depended with one another. In such case, facade can act as a coordinator and decouple the dependencies between the subsystems.
  • We can use the Factory pattern with Facade to provide a better interface to client systems.

Usage in Java

In javax.faces.context, ExternalContext internally uses ServletContext, HttpSession, HttpServletRequest, HttpServletResponse, etc. It allows the Faces API to be unaware of the nature of its containing application environment.


Bridge Design Pattern

When we have interface hierarchies in both interfaces as well as implementations, then the BRIDGE design pattern is used to decouple the interfaces from implementation and hiding the implementation details from the client programs.

According to the GoF bridge design pattern is: Decouple an abstraction from its implementation so that the two can vary independently.

The Bridge Pattern’s intent is to put the abstraction and implementation into two different class hierarchies so that both can be extend independently.

Adapter Pattern vs Bridge Pattern

The Adapter Design Pattern helps it two incompatible classes to work together. But the Bridge Design Pattern decouples the abstraction and implementation by creating two different hierarchies

When to Use and other points

  • Should be used when we have a need to switch implementation at runtime.
  • The client should not be impacted if there is a modification in implementation of abstraction.
  • Best used when you have multiple implementations.
  • Creates two different hierarchies. One for abstraction and another for implementation.
  • Avoids permanent binding by removing the dependency between abstraction and implementation.
  • We create a bridge that coordinates between abstraction and implementation.
  • Abstraction and implementation can be extended separately.

Usage in JDK

  • AWT (It provides an abstraction layer which maps onto the native OS the windowing support.)
  • JDBC


Decorator Design Pattern

The primary intent of the Decorator Design Pattern is to attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality.

The Decorator Pattern facilitates us when we need to extend the functionality of an object dynamically without having to change the original class source or using inheritance. This is accomplished by creating an object wrapper referred to as a Decorator around the actual object.

When to use the Decorator Design Pattern

Use the Decorator pattern in the following cases:

  • To add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
  • For responsibilities that can be withdrawn.
  • When extension by sub-classing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for sub-classing.
  • It’s easy to maintain and extend when the number of choices are more.

Usage in Java

We use the decorator pattern mostly in Java IO classes, such as FileReader, BufferedReader etc.

  • The disadvantage of decorator pattern is that it uses a lot of similar kind of objects (decorators).

 

No comments:

Post a Comment