The of Java design pattern -- adapter pattern

1. What is adapter mode?

Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Adapter Pattern: transforms the interface of a class into another interface expected by the client, so that two classes that cannot work together due to interface mismatch can work together.

Speaking: this mode is used for adaptation. It converts incompatible interfaces into compatible interfaces, so that classes that cannot work together due to incompatible interfaces can work together. For example, in real life, the USB adapter acts as an adapter to make two incompatible interfaces work together through switching.

2. Adapter mode definition

① Target, target role

This role defines what kind of interface to convert other classes, that is, our desired interface. The IUserInfo interface in the example is the target role.

② . Adaptee source role

The "who" you want to convert into the target role is the source role. It is an existing and well running class or object. After being wrapped by the adapter role, it will become a new and beautiful role.

③ Adapter, adapter role

The core role of the adapter mode. The other two roles are existing roles, and the adapter role needs to be newly established. Its responsibility is very simple: how to convert the source role to the target role? By inheritance or class association.

3. General code implementation of adapter pattern

/**
 * Target role
 */
public interface Target {
    void t1();
    void t2();
    void t3();
}
/**
 * Target role implementation class
 */
public class ConcreteTarget implements Target{

    @Override
    public void t1() {
        System.out.println("Target role t1 method");
    }

    @Override
    public void t2() {
        System.out.println("Target role t2 method");
    }

    @Override
    public void t3() {
        System.out.println("Target role t3 method");
    }
}
/**
 * Source role: to convert the source role to the target role
 */
public class Adaptee {

    public void a1(){
        System.out.println("Source role a1 method");
    }

    public void a2(){
        System.out.println("Source role a2 method");
    }

    public void a3(){
        System.out.println("Source role a3 method");
    }
}

Inheritance based class adapter

/**
 * Adapter role
 */
public class Adapter extends Adaptee implements Target{

    @Override
    public void t1() {
        super.a1();
    }

    @Override
    public void t2() {
        super.a2();
    }

    @Override
    public void t3() {
        super.a3();
    }
}

Composition based object adapter

public class AdapterCompose implements Target{

    private Adaptee adaptee;

    public AdapterCompose(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    @Override
    public void t1() {
        adaptee.a1();
    }

    @Override
    public void t2() {
        adaptee.a2();
    }

    @Override
    public void t3() {
        adaptee.a3();
    }
}

Test:

public class AdapterClient {

    public static void main(String[] args) {
        // Original business logic
        Target target = new ConcreteTarget();
        target.t1();

        // Add adapter business logic based on inheritance
        Target target1 = new Adapter();
        target1.t1();

        // Add adapter business logic based on combination
        Target target2 = new AdapterCompose(new Adaptee());
        target2.t1();
    }
}

Print results:

The adapter pattern can be implemented in two ways: class adapter and object adapter. Among them, the class adapter is implemented by inheritance relationship, and the object adapter is implemented by composition relationship. In the actual development, the selection basis is as follows:

① If there are not many Adaptee interfaces, both implementation methods can be used.

② If there are many Adaptee interfaces, and the definitions of Adaptee and ITarget interfaces are mostly the same, we recommend using class adapter, because the adapter reuses the interface of the parent class Adaptee, and the amount of code of the adapter is less than that of the object adapter.

③ If there are many Adaptee interfaces and most of the Adaptee and ITarget interface definitions are different, we recommend using object adapters because the composite structure is more flexible than inheritance.

4. Adapter mode benefits

① The adapter mode allows two unrelated classes to run together, as long as the role of the adapter can handle them.

② . increased class transparency

We access the Target role, but the specific implementation is delegated to the source role, which is transparent to high-level modules and does not need to be concerned.

③ The reusability of classes is improved

The source character can still be used normally in the original system, and can also act as a new actor in the target character.

④ Very flexible

The adapter can be removed at any time without affecting a lot of code.

5. Adapter mode application scenario

① . modify the used interface

When an interface that has been put into production needs to be modified, it is best to use the adapter.

② . unify the interface design of multiple classes

For example, for sensitive word filtering, several third-party interfaces need to be called, and the method name and method parameters of each interface are different. At this time, the adapter mode is used to adapt all third-party interfaces to a unified interface definition.

③ . compatible with old version interface

For example, JDK1.0 contains a class Enumeration that traverses the collection container. JDK2.0 reconstructs this class, renames it Iterator class, and optimizes its code implementation. However, considering that if the Enumeration is directly deleted from JDK2.0, if the project using JDK1.0 is switched to JDK2.0, the code will fail to compile. In order to avoid this situation, we must change all the places where Enumeration is used in the project to use Iterator.

The replacement of Enumeration to Iterator for a single project is barely acceptable. However, there are too many projects developed in Java. An upgrade of JDK will cause all projects to compile and report errors without code modification, which is obviously unreasonable. This is what we often call incompatible upgrades. In order to be compatible with the old code using the lower version JDK, we can temporarily retain the Enumeration class and replace its implementation with calling Itertor directly.

public class Collections {
  public static Emueration emumeration(final Collection c) {
    return new Enumeration() {
      Iterator i = c.iterator();
      
      public boolean hasMoreElments() {
        return i.hashNext();
      }
      
      public Object nextElement() {
        return i.next():
      }
    }
  }
}

④ . adapt to data in different formats

6. Agent bridge decorator adapter difference

① The proxy mode defines a proxy class for the original class without changing the original class interface. The main purpose is to control access rather than strengthen functions, which is the biggest difference between it and the decorator mode.

② Bridge mode: the purpose of bridge mode is to separate the interface part from the implementation part, so that they can be changed easily and relatively independently.

③ Decorator mode: the decorator mode enhances the functions of the original class without changing the original class interface, and supports the nested use of multiple decorators.

④ Adapter mode: adapter mode is an ex post remedy strategy. The adapter provides different interfaces from the original class, while the proxy mode and decorator mode provide the same interfaces as the original class.

Posted by edawg on Sun, 28 Nov 2021 23:34:19 -0800