Adapter mode

1, Overview

First, we need to introduce what the adapter mode does

Convert the interface of a class into another interface that the customer wants.


In short, the adapter mode is to enable us to interact with incompatible classes through certain processing, and the processing process or processing class is what we call the adapter, and the two ends of the adapter are the adaptees and the adaptees
A common example is our socket and charger. Usually, the voltage of our socket is the rated voltage of 220V, but if we want to charge the mobile phone, it is certainly impossible to directly 220V. At this time, we need a plug to convert the 220V of the socket into the voltage suitable for our mobile phone. In this case, the mobile phone needs our adaptees, and the socket is the adapter, The mobile phone charging plug acts as an adapter.

There are many adapter modes, such as class adapter, object adapter, bidirectional adapter... The introduction and differences of each mode will not be introduced first, but will be put in the summary.

2, Roles and responsibilities

Target:

  • Define the domain specific interfaces used by the Client
  • To be adapted to him (the adapted)

Client

  • Cooperate with object conforming to Target interface
  • Call Adaptee

Adaptee

  • Define an existing interface that needs to be adapted
  • Need to adapt to others (those who want to adapt)

Adapter

  • Adapt the interface of Adaptee to the Target interface

For the example of socket and mobile phone charger, our socket with 220V rated voltage is Adaptee, and our mobile phone charging socket is Target. To change the 220V voltage into a voltage suitable for charging the mobile phone, the charger exists as an Adapter in this link.

3, Class adapter

First, let's look at the class adapter. The UML diagram is as follows

As can be seen from the above figure, the class Adapter mode is to enable the Adapter to implement the abstract interface of the Target and then inherit the Adaptee. The specific adaptation process is to adapt the SpecificRequest() method of the Adaptee in the Resuest() method of our Adapter, Make the Request() method of the Adapter return the Adaptee we need for our use.

Let's implement the class adapter mode through code. We still use the example of socket and charger
First, create a class that mimics the socket, in which the method returns a 220V voltage value

/**
 * @author ZhongJing </p>
 * @Description Socket (type to be fitted)</p>
 */
public class Voltage220V {

    public int output220V() {
        int src = 220;
        System.out.println("Voltage=" + src + "Crouch");
        return src;
    }

}

Then we define a class to simulate the rated voltage required by the mobile phone

/**
 * @author ZhongJing </p>
 * @Description Rated voltage of mobile phone (adapter)</p>
 */
public interface IVoltage5V {

    public int output5V();

}

With Adaptee and Target, we need an Adapter to convert the 220V voltage into the charging voltage supported by the mobile phone

/**
 * @author ZhongJing </p>
 * @Description Adapter</p>
 */
public class VoltageAdapter extends Voltage220V implements IVoltage5V {

    @Override
    public int output5V() {
        // Obtain 220V voltage
        int srcV = output220V();
        // Processing voltage, converted to 5V
        int dstV = srcV / 44;
        return dstV;
    }
}

Create a mobile phone class. One of the methods is to charge the analog mobile phone. The method requires a parameter of rated voltage Target

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Phone {

    public void charging(IVoltage5V voltage) {
        if (voltage.output5V() == 5) {
            System.out.println("The voltage is 5 V,Can charge~");
        } else if (voltage.output5V() > 5) {
            System.out.println("Voltage greater than 5 V,Can't charge~");
        }
    }

}

Let's write a main method to run the code we write to verify whether it is correct

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Client {

    public static void main(String[] args) {

        System.out.println("Class adapter mode");

        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());

    }

}

The operation results are as follows:

Class adapter mode
 Voltage=220 Crouch
 The voltage is 5 V,Can charge~

4, Object adapter

The UML diagram of the object adapter is as follows:

You can see that the object adapter does not inherit the Adaptee, but uses the Adaptee through association (member attribute)
The only difference between class adapter and class adapter is the writing method of adapter. The specific code is as follows:

/**
 * @author ZhongJing </p>
 * @Description Adapter</p>
 */
public class VoltageAdapter implements IVoltage5V {

    private Voltage220V voltage220V;

    public VoltageAdapter() {
    }

    public VoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public int output5V() {
        int dst = 0;
        if (voltage220V != null) {
            int src = voltage220V.output220V();
            System.out.println("Use object adapter for adaptation");
            dst = src / 44;
            System.out.println("After adaptation, the output voltage is:" + dst);
        }
        return dst;
    }
}

Other codes and class adapters are the same, so we won't repeat it. Let's write a test code to test it

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Client {

    public static void main(String[] args) {

        System.out.println("Object Adapter Pattern ");

        Phone phone = new Phone();
        phone.charging(new VoltageAdapter(new Voltage220V()));

    }

}

The operation results are as follows:

Object Adapter Pattern 
Voltage=220 Crouch
 Use object adapter for adaptation
 After adaptation, the output voltage is: 5
 The voltage is 5 V,Can charge~

The object adapter mode is more flexible than the class adapter mode. Through our test code, we can find that our Adaptee is passed in through the constructor, This makes it easier for us to extend our code (polymorphic). Moreover, if the class adapter is not an interface but also a class, Java does not support multiple inheritance, which is a very serious problem.

5, Bidirectional adapter

The bidirectional adapter is actually a variant of the object adapter
That is, when there are references to both Target and Adaptee in the adapter, the adapter defines methods for both. You can adapt the Target to Adaptee or Adaptee to Target without distinguishing who is the adapter and who is the Adaptee.
The UML diagram is as follows:

The code is roughly as follows

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Adapter implements Target, Adaptee {

    private Target target;

    private Adaptee adaptee;

    public Adapter(Target target) {
        this.target = target;
    }

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void setTarget(Target target) {
        this.target = target;
    }

    public void setAdaptee(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void specificRequest() {
        // Adaptation code
        target.request();
    }

    @Override
    public void request() {
        // Adaptation code
        adaptee.specificRequest();
    }
}

6, Summary

This article introduces three adapter modes: class adapter, object adapter and bidirectional adapter

In general, the advantages of the adapter mode are as follows:

  • Decouple the target class from the adapter class, and reuse the original class through an intermediate adapter without changing the original code
  • It has high flexibility and scalability

Object adapter and class adapter also have their own advantages and disadvantages

The advantage of class adapter is that the adapter class inherits Adaptee, so we can modify and rewrite some methods of Adaptee in the adapter class, which is more flexible
The disadvantage is that the class adapter needs to inherit Adaptee. When our Target is a class rather than an interface, the class adapter is not suitable for us.

The advantage of the object adapter is that it includes Adaptee as a member attribute through the association relationship, so we can run polymorphism to adapt Adaptee and its subclasses to the Target. Of course, this is on the premise that Adaptee and its subclasses follow the "Richter replacement principle".

Keywords: Java Design Pattern

Added by dugindog on Mon, 27 Dec 2021 14:10:24 +0200