Adapter Pattern
Adapter Pattern is a bridge between two incompatible interfaces. This type of design pattern belongs to structural pattern, which combines the functions of two independent interfaces.
This pattern involves a single class that is responsible for adding independent or incompatible interface functions. For a real example, the card reader is used as an adapter between the memory card and the notebook. You insert the memory card into the card reader, and then insert the card reader into the notebook, so that you can read the memory card through the notebook.
- The adapter mode converts the interface of a class into another interface expected by the client. The main purpose is compatibility, so that the two classes that cannot work together due to interface mismatch can work together. Its alias is wrapper
- The adapter mode is a structural mode
- Adapter mode and adapter mode are divided into three categories: adapter mode and adapter mode
Case 1: application example of class I adapter mode (charger as an example)
The charger itself is equivalent to the Adapter,220V AC is equivalent to SRC (i.e. the Adaptee), and our target DST (i.e. the target) is 5V DC
//Adapted class public class Voltage220V { //Output 220V voltage public int output220V() { int src = 220; System.out.println("Voltage=" + src + "Crouch"); 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 //220V voltage obtained int srcV = output220V(); int dstV = srcV / 44 ; //Convert to 5v return dstV; } }
public class Phone { //charge 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, Can't charge~~"); } } }
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(" === Class adapter mode ===="); Phone phone = new Phone(); phone.charging(new VoltageAdapter()); } }
Class adapter mode benefits
- Because it inherits the src class, it can rewrite the methods of the sre class according to the requirements, which enhances the flexibility of the Adapter
Class adapter mode disadvantages
- Java is a single inheritance mechanism, so the class adapter needs to inherit the sre class, because this requires dst to be an interface, which has certain limitations
- The methods of src class will be exposed in the Adapter, which also increases the cost of use
Case 2: object adapter mode
- The basic idea is the same as the Adapter mode of the class, except that the Adapter class is modified instead of inheriting the src class, but holding an instance of the src class to solve the problem of compatibility. That is, hold the sre class, implement the dst class interface, and complete the adaptation of sre - > dst
- According to the "composite Reuse Principle", try to use association relationship (aggregation) in the system to replace inheritance relationship
- Object adapter pattern is a common pattern of adapter pattern
Modify the Adapter class
//adapter class public class VoltageAdapter implements IVoltage5V { private Voltage220V voltage220V; // Association - aggregation //Pass in a Voltage220V instance through the 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 System.out.println("Use the object adapter for adaptation~~"); dst = src / 44; System.out.println("After adaptation, the output voltage is=" + dst); } return dst; } }
Input Voltage220V through construction method
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())); } }
Case 3: interface adapter mode
- Default adapter pattern or default adapter pattern.
- When you do not need to implement all the methods provided by the interface, you can first design an abstract class to implement the 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
- This applies when an interface does not want to use all its methods.
public interface Interface4 { public void m1(); public void m2(); public void m3(); public void m4(); }
//In AbsAdapter, we implement the method of Interface4 by default public abstract class AbsAdapter implements Interface4 { //Default implementation public void m1() { } public void m2() { } public void m3() { } public void m4() { } }
public class Client { public static void main(String[] args) { AbsAdapter absAdapter = new AbsAdapter() { //We just need to override. We need to use interface methods @Override public void m1() { System.out.println("Used m1 Method of"); } }; absAdapter.m1(); } }
Source code analysis of the application of adapter pattern in spring MVC framework
Core code
Actual call handler
Simulate spring MVC adapter
//Multiple Controller implementations public interface Controller { } class HttpController implements Controller { public void doHttpHandler() { System.out.println("http..."); } } class SimpleController implements Controller { public void doSimplerHandler() { System.out.println("simple..."); } } class AnnotationController implements Controller { public void doAnnotationHandler() { System.out.println("annotation..."); } }
public class DispatchServlet { public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>(); public DispatchServlet() { handlerAdapters.add(new AnnotationHandlerAdapter()); handlerAdapters.add(new HttpHandlerAdapter()); handlerAdapters.add(new SimpleHandlerAdapter()); } public void doDispatch() { // This simulates spring MVC fetching the handler object from the request, // The adapter can get the desired Controller HttpController controller = new HttpController(); // AnnotationController controller = new AnnotationController(); //SimpleController controller = new SimpleController(); // Get the corresponding adapter HandlerAdapter adapter = getHandler(controller); // Execute the corresponding controller method through the adapter adapter.handle(controller); } public HandlerAdapter getHandler(Controller controller) { //Traversal: return the corresponding adapter according to the obtained controller(handler) for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(controller)) { return adapter; } } return null; } public static void main(String[] args) { new DispatchServlet().doDispatch(); // http... } }
class HttpHandlerAdapter implements HandlerAdapter { public void handle(Object handler) { ((HttpController) handler).doHttpHandler(); } public boolean supports(Object handler) { return (handler instanceof HttpController); } } class AnnotationHandlerAdapter implements HandlerAdapter { public void handle(Object handler) { ((AnnotationController) handler).doAnnotationHandler(); } public boolean supports(Object handler) { return (handler instanceof AnnotationController); } }