Adapter pattern: description, functions and features, work tips

An adapter is a structural design pattern used to organize and implement object methods that cannot be modified using a specially designed interface. Otherwise, we can say that this is a structural template that allows objects with incompatible interfaces to interact with each other.

Description

The adapter pattern adapts between classes and objects. Like any adapter in the world around us, a template is an interface or a bridge between two objects. In the real world, we have adapters for power supplies, for hard drives, for headphones, for camera memory cards and so on. For example, consider several adapters for memory cards. If you cannot connect the camera’s memory card to the laptop directly, you can use the adapter: the camera’s memory card is connected to the adapter, and the adapter to the laptop connector. Thus, the problem of incompatibility of the interfaces will be resolved.

Adapter: design pattern and interface




In the case of software development, things are roughly the same. It is possible to imagine a situation when there is a class waiting for some type of object, and there is an object offering the same functionality, but with a different interface. Of course, it will be beneficial to use both of them, so as not to implement one of the interfaces repeatedly and not to modify existing classes. It is in this situation that it would be wise to use an adapter for software design.





Implementation

The figure below shows the UML class diagram of the Adapter pattern.

Adapter: UML diagram




Classes and objects involved in the design pattern:

  1. (Target) - defines the domain-specific interface that Client uses.
  2. (Adapter) - adapts the interface (Adaptee) to the target interface.
  3. (Adaptee) - defines the existing interface that needs to be adapted.
  4. (Client) - interacts with objects corresponding to the (Target) interface.

Application

The adapter pattern is used in the following cases:

  • When there is a class (Target) that calls methods defined in the interface. In addition, there is another class (Adapter) that does not implement the interface, but implements operations and methods that must be called from the first class through the interface. The programmer does not have the ability to change any of the existing codes. The adapter implements its interface and becomes a bridge between the two classes.
Adapter Pattern: building a project




  • When, when writing a class (Target) for general use, it is important to rely on some common interfaces, and the developer has some implemented classes that do not implement the interface. Also this class (Target) must be callable.

A good example for using the adapter is the shell used to host third-party libraries and structures: most applications that use third-party libraries use the adapter as an intermediate layer between the application and the third-party library to separate the application from the library. If you need to use a different library, only the adapter is required for the new library without the need to change the application code.





Delegation Based Object Adapters

An object (Adapter) is a classic example of an adapter pattern. It uses composition, and (Adaptee) delegates calls to itself, which is not available to class adapters that extend (Adaptee). This behavior gives us several advantages over class adapters, however class adapters can be implemented in languages ​​that allow multiple inheritance. The main advantage is that (Adapter) adapts not only (Adaptee), but also all its subclasses. All these subclasses exist with one “small” limitation: they all cannot add new methods, because the mechanism used is delegation. Thus, for any new method, the adapter must be modified or extended to provide new methods. The main disadvantage is that it requires writing new code to delegate all the necessary requests to the adapter.

Class Adapters Based on (Multiple) Inheritance

Class adapters can be implemented in languages ​​that support multiple inheritance. The Java, C #, or PHP programming languages ​​do not support multiple inheritance, but they do have interfaces. Thus, such patterns cannot be easily implemented in these languages. A good example of a programming language where design can be easily implemented is C.

Pattern Adapter uses inheritance instead of composition. This means that instead of delegating calls (Adaptee), it inherits it. In conclusion, the class adapter must subclass both (Target) and (Adapter) itself.

Multiple Inheritance Adapter




With this approach, there are advantages and disadvantages:

  • A pattern adapts a specific class (adapter). The class extends this adaptation. If that subclass, it cannot be adapted by an existing adapter.
  • The template does not require all the code necessary for delegation, which must be written for the class (Adapter).
  • If an object (Target) is represented by an interface rather than a class, we can talk about “class” adapters, because we can implement as many interfaces as we want.

Two way adapters

Two-way adapters are adapters that implement both interfaces: both (Target) and (Adaptee). The adapted object can be used as (Target) in new systems working with classes (Target), or as (Adaptee) in other systems working with classes (Adaptee). If we go further in this direction, then we can have adapters that implement the nth number of interfaces that adapt to n-systems. Two-way adapters and n-way adapters are difficult to implement on systems that do not support multiple inheritance. If the adapter must extend the class (Target), it cannot extend another class, such as (Adaptee), therefore (Adaptee) must be an interface, and all calls can be delegated from the adapter to the object (Adaptee).

Using the Adapter template in VR development




In addition, if (Target) and (Adapter) are similar, then the adapter should simply delegate requests from the (Target) class to the (Adapter) class, and if (Target) and (Adaptee) are not alike, then the adapter may need to convert data structures between them and implement the operations required for (Target), but not implemented in the class (Adaptee).

Implementation example

Suppose we have a (Bird) class with the fly () and makeSound () methods. And also a class (ToyDuck) with the Squeak () method. Let's say that we have few objects (ToyDuck) and we want to use objects (Bird) instead of them. Birds have similar functionality, but implement a different interface, so we cannot use them directly. Therefore, we will use the adapter template. Here, our (Client) will be (ToyDuck), and (Adaptee) will be (Bird). The following is an example implementation of designing the Adapter pattern in Java, one of the most common programming languages.

interface Bird { public void fly(); public void makeSound(); } class Sparrow implements Bird { public void fly() { System.out.println("Flying"); } public void makeSound() { System.out.println("Chirp Chirp"); } } interface ToyDuck { public void squeak(); } class PlasticToyDuck implements ToyDuck { public void squeak() { System.out.println("Squeak"); } } class BirdAdapter implements ToyDuck { Bird bird; public BirdAdapter(Bird bird) { this.bird = bird; } public void squeak() { bird.makeSound(); } } class Main { public static void main(String args[]) { Sparrow sparrow = new Sparrow(); ToyDuck toyDuck = new PlasticToyDuck(); ToyDuck birdAdapter = new BirdAdapter(sparrow); System.out.println("Sparrow..."); sparrow.fly(); sparrow.makeSound(); System.out.println("ToyDuck..."); toyDuck.squeak(); System.out.println("BirdAdapter..."); birdAdapter.squeak(); } }
      
      



Suppose we have a bird that can make Sound (), and a plastic toy duck that can squeak - Squeak (). Now suppose our (Client) changes the requirement and wants (ToyDuck) to execute Sound (), but how?

Design Example Based on Adapter Pattern




The solution is that we simply change the implementation class to a new adapter class and tell the client to pass the bird instance to this class. That's all. Now changing only one line, we will teach (ToyDuck) to tweet like a sparrow.




All Articles