Design pattern - adapter pattern (detailed explanation of class adapter, object adapter and interface adapter)

Article catalogue

Adapter mode

Adapter pattern transforms the interface of a class into another interface expected by the client. The main purpose is compatibility, so that two classes that cannot work together due to interface mismatch can work together. Also known as wrapper, it belongs to structural mode. Adapter patterns are mainly divided into three categories: class adapter pattern, object adapter pattern and interface adapter pattern

working principle Convert the interface of one class into another, so that the classes whose original interfaces are incompatible can be compatible. From the user's point of view, the Adaptee is decoupled /. The user calls the target interface method transformed by the adapter, and then the adapter calls the relevant interface method of the Adaptee. The user receives the feedback result and feels that he is only interacting with the target interface.

In short, the adapter mode is like a plug converter, which allows plugs and sockets of different standards to be used together. The socket is the original interface, and the plug is the interface expected by users. Or analog power adapter to convert the original 220V voltage into 5V voltage, etc.

Class Adapter

As the name suggests, the Adapter is implemented through classes, and the information of the adapted class is obtained by inheriting and implementing the interface through classes, and the conversion output is rewritten to the adapted interface. That is, the Adapter class implements the dst class interface by inheriting the src class to complete the adaptation of src - > dst.

//Adapted class
public class Voltage220V {
	public int output220V() {
		int src = 220;
		System.out.println("Voltage=" + src);
		return src;
	}
}

//Adapter interface
public interface IVoltage5V {
	public int output5V();
}

//adapter class 
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
	@Override
	public int output5V() {
		// TODO Auto-generated method stub
		//Obtain 220V voltage
		int srcV = output220V();
		int dstV = srcV / 44 ; //Convert to 5v
		return dstV;
	}
}

//call
public class Phone {
	public void charging(IVoltage5V iVoltage5V) {
		if(iVoltage5V.output5V() == 5) {
			System.out.println("The voltage is 5 v,Can charge");	
		    } else if (iVoltage5V.output5V() > 5) {
			System.out.println("Voltage greater than 5 v,Non rechargeable");
		}
	}
}

//test
public class Client {
	public static void main(String[] args) {
		System.out.println("===Class adapter test===");
		Phone phone = new Phone();
		phone.charging(new VoltageAdapter());
	}
}
copy

Advantages and disadvantages:

  1. There are certain limitations. Because the class adapter needs to inherit the src class, and Java is a single inheritance mechanism, dst must be an interface.
  2. The methods of src class will be exposed in the Adapter, with high coupling.
  3. The method of src class can be rewritten according to requirements, which enhances the flexibility of the Adapter.

object adapter

As the name suggests, the adapter is implemented through the instance object (passed by the constructor), rather than inheritance. The rest are basically similar adapters. That is: hold src class, implement dst class interface, and complete the adaptation of src - > dst.

(insert anti climbing information) CSDN address of blogger: https://wzlodq.blog.csdn.net/

//Adapted class (invariant)
public class Voltage220V {
	public int output220V() {
		int src = 220;
		System.out.println("Voltage=" + src);
		return src;
	}
}

//Adapter interface (unchanged)
public interface IVoltage5V {
	public int output5V();
}

//adapter class 
public class VoltageAdapter  implements IVoltage5V {
	private Voltage220V voltage220V;
	//constructor 
	public VoltageAdapter(Voltage220V voltage220v) {
		this.voltage220V = voltage220v;
	}

	@Override
	public int output5V() {
		int dst = 0;
		if(null != voltage220V) {
			int src = voltage220V.output220V();//Obtain 220v voltage
			dst = src / 44;
		}
		return dst;
	}
}

//Call (unchanged)
public class Phone {
	public void charging(IVoltage5V iVoltage5V) {
		if(iVoltage5V.output5V() == 5) {
			System.out.println("The voltage is 5 v,Can charge");	
		    } else if (iVoltage5V.output5V() > 5) {
			System.out.println("Voltage greater than 5 v,Non rechargeable");
		}
	}
}

//test
public class Client {
	public static void main(String[] args) {
		System.out.println("===object adapter ===");
		Phone phone = new Phone();
		VoltageAdapter VoltageAdapter = new VoltageAdapter(new Voltage220V());
		phone.charging(VoltageAdapter);
	}
}
copy

Advantages and disadvantages:

  1. Decoupling inheritance solves the limitation that class adapters must inherit src, and dst is no longer required to be an interface.
  2. Low cost and more flexible.

Interface adapter

Inheritance can be decoupled. Can we decouple from the interface?

The interface adapter, also known as the default adapter mode, is suitable for situations where an interface does not want to use all its methods. When you do not need to implement all the methods provided by the interface, you can first design an abstract class implementation interface and provide a default implementation (empty method) for each method in the interface. Then the subclass of the abstract class can selectively override some methods of the parent class to meet the requirements.

//Adapted class (invariant)
public class Voltage220V {
	public int output220V() {
		int src = 220;
		System.out.println("Voltage=" + src);
		return src;
	}
}

//Adapter interface
public interface IVoltage5V {
	public int output5V();
	public void m2(); //Redundant unimportant method in interface
	public String m3();
}
//Abstract adapter
public abstract class AbsAdapter extends Voltage220V implements IVoltage5V{
    @Override //Implement all methods of the interface with null method
    public int output5V() {
        return 0;
    }
    @Override
    public void m2() {
    }
    @Override
    public String m3() {
        return null;
    }
}

//Call (unchanged)
public class Phone {
	public void charging(IVoltage5V iVoltage5V) {
		if(iVoltage5V.output5V() == 5) {
			System.out.println("The voltage is 5 v,Can charge");
		} else if (iVoltage5V.output5V() > 5) {
			System.out.println("Voltage greater than 5 v,Non rechargeable");
		}
	}
}

//test
public class Client {
	public static void main(String[] args) {
		System.out.println("===Interface adapter===");
		AbsAdapter absAdapter = new AbsAdapter() { //Form of anonymous inner class
			@Override //Override interface methods as needed
			public int output5V() {
				System.out.println("Used output5V Method of");
				int srcV = output220V();
				int dstV = srcV / 44 ; //Convert to 5v
				return dstV;
			}
		};
		Phone phone = new Phone();
		phone.charging(absAdapter);
	}
}
copy

Advantages and disadvantages:

  1. The interface method can be rewritten flexibly and conveniently.
  2. Because it is in the form of anonymous inner class, it is not conducive to code reuse.

summary

The above three forms are named according to the form src gives to the Adapter:

  1. Class Adapter: given by class, in the Adapter, src is regarded as a class and inherited
  2. Object Adapter: given by object, src is regarded as an object and held in the Adapter
  3. Interface Adapter: it is given by interface. In the Adapter, src is used as an interface to implement

The biggest function of the Adapter mode is to integrate the incompatible interfaces. In the actual development, the implementation is not limited to the three classic forms we explain.

Posted by wizzard on Sun, 08 May 2022 04:53:00 +0300