List of articles
-
- Preface
- Adapter pattern
-
- 1、 Definition
- 2、UML Class diagram
- 3、 Practical examples
- 4、 summary
-
- 1) advantage
- 2) shortcoming
- 3) Applicable scenario
- SpringMVC The underlying adapter pattern
- Reference resources
Preface
The adapter pattern is one of the most common design patterns , It is not only widely used in code development , It’s also common in daily life . Like the power adapter on the laptop , It can be used in 110~ 220V Between changes in power , And the laptop works , This is the most direct example of the adapter pattern , At the same time, it is also the embodiment of his thoughts , To put it simply , The adapter pattern is to put a class ( Interface ) Convert to other classes ( Interface ).
Adapter pattern
1、 Definition
Adapter pattern , Also called packaging mode , refer to ** Transform the interface of one class into another interface expected by the client , So that the two classes that could not work together due to interface mismatch can work together .** We can solve the problem of interface incompatibility by adding an adapter class , This adapter class is equivalent to the adapter of the notebook .
Depending on the relationship between the adapter class and the adapter class , Adapter pattern can be divided into object adapter and class adapter , In object adapter mode , Between the adapter and the adapter is relation Relationship ; In the class adapter pattern , Between the adapter and the adapter is Inherit ( Or implementation ) Relationship .
2、UML Class diagram
The adapter pattern contains several roles , They are :
Target( The target character ): This role defines what interface other classes translate to , It can be an abstract class or interface , It can also be a specific class .
Adaptee( The source role ): Who do you want to turn into the target character , This “ who ” That’s the source role , It’s already there 、 A well-functioning class or object .
Adapter( Adapter role ): The core role of the adapter pattern , The responsibility is to transform the source role into the target role by inheritance or class association .
3、 Practical examples
Know what roles and UML After class diagram , We can write the code , For ease of understanding , We use the example of charger in our life to explain the adapter , Now there’s a cell phone to charge , The required rated voltage is 5V, And the voltage of household alternating current is standard 220V, In this case, to charge, an adapter is needed for voltage conversion .
It’s not hard to put the three into the class diagram we drew above , The charger itself is equivalent to Adapter,220V Alternating current is equivalent to Adaptee, Our goal Target yes 5V Direct current .
Target Target interface
public interface Voltage5 {
int output5V();
}
The implementation class of the target interface
public class ConcreteVoltage5 implements Voltage5{
@Override
public int output5V() {
int src = 5;
System.out.println(" Target voltage :" + src + "V");
return src;
}
}
Adaptee class
public class Voltage220 {
// Output 220V The voltage of
public int output220V() {
int src = 220;
System.out.println(" The source voltage is :" + src + "V");
return src;
}
}
Adapter class : complete 220V-5V The transformation of
public class VoltageAdapter extends Voltage220 implements Voltage5 {
@Override
public int output5V() {
// Get the source voltage
int adaptee = super.output220V();
// Start the adaptation operation
System.out.println(" Object adapter works , Start to adapt the voltage ");
int dst = adaptee / 44;
System.out.println(" Output voltage after adaptation :" + dst + "V");
return dst;
}
}
Through the transformation of the adapter class , We can 220V The voltage is converted to what we need 5V The voltage is on , Write a scenario class test :
/**
* Adapter pattern
*/
public class Client {
public static void main(String[] args) {
Voltage5 voltage5 = new ConcreteVoltage5();
voltage5.output5V();
// Create an adapter object
VoltageAdapter2 voltageAdapter = new VoltageAdapter2();
// Switching voltage
voltageAdapter.output5V();
}
}
Results output
Target voltage :5V
The source voltage is :220V
Object adapter works , Start to adapt the voltage
Output voltage after adaptation :5V
I said before. , There are two adapter modes , What we introduced above is the implementation of class adapter through inheritance , There is also an object adapter , It is implemented by associating the adapter with the adapter , Its general class diagram is shown below :
The code aspect is also relatively simple , Refer to the above example to change the writing method of inheritance to association , The code is not posted , The reader can write for himself .
4、 summary
Let’s summarize the adapter pattern
1) advantage
- It can realize the decoupling between the target class and the desired role class . The adapter pattern lets two unrelated classes run together , As long as the adapter role can handle them .
- Increased class transparency . Encapsulate the specific business implementation process in the adapter class , Transparent to client classes , And it improves the reusability of the adapter , The same adapter class can be reused in multiple different systems .
- Flexibility and scalability are very good . One day , Suddenly I don’t want an adapter , That’s all right. , Just delete the adapter , No other code modify , It’s basically like a flexible component , Use if you want , Uninstall if you don’t want to .
2) shortcoming
-
The class adapter : By way of inheritance , Yes Java For a language that doesn’t support multiple inheritance , Only one adapter class can be adapted at a time , Not very convenient
-
Object adapter : Compared to the class adapter pattern , Some of the ways to replace adapter classes in an adapter are cumbersome . If you must replace one or more methods of the adapter class , You can first make a subclass of the adapter class , Replace the methods of the adapter class , Then, the subclass of the adapter class is regarded as the real adapter for adaptation , The implementation process is more complex .
3) Applicable scenario
- When it needs to be modified to the online interface , Adapter mode is probably the most appropriate mode .
- The system expanded , You need to use an existing or new class , But the class does not conform to the interface support of the system , At this point, you can introduce the adapter class to do the transformation .
SpringMVC The underlying adapter pattern
Here we extend the knowledge of adapter pattern , I think I did Java All the developers know SpringMVC, This framework can help us access the front-end requests to the back-end corresponding controller On the way , Then return the result to the back end , Its bottom layer actually uses adapter mode .
SpringMVC The adapter pattern in is mainly used to execute the target Controller Request handling method in . In its underlying processing ,DispatcherServlet As the user ,HandlerAdapter As the expected interface , The specific adapter implementation class is used to adapt the target class ,Controller As a class that needs to be adapted .
Why are you in Spring MVC Using adapter mode ?Spring MVC Medium Controller There are many kinds , Different types of Controller Processing requests in different ways . If you don’t use adapter mode ,DispatcherServlet Get the corresponding type of Controller, So every time you add a type of Controller You need to add one if else Judge instance of, This violates the opening and closing principle of the design mode —— Open to expansion , Turn off for changes .
that SpringMVC How to deal with it ? Let’s take a look at the source code , The first is the adapter interface HandlerAdapter,
public interface HandlerAdapter {
boolean supports(Object var1);
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
The adapter class of this interface corresponds to Controller, Every custom one Controller You need to define an implementation HandlerAdapter Adapter for . for instance , There is an adapter class HttpRequestHandlerAdapter
, This class is the implementation of HandlerAdapter Interface , This is its source :
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
When Spring After the container starts , All defined adapter objects will be stored in one List Collection , When a request comes ,DispatcherServlet Will pass handler Find the corresponding adapter for type , And return the adapter object to the user , Then you can unify the handle
Method to call Controller Method for processing requests in .
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//.........................
// Find the adapter that matches the current request
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
}
// Ergodic set , Find the right matcher
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
}
thus , be-all controller All of them will be handed over to HandlerAdapter Handle , There’s no need for a lot of if-else Sentence judgment , At the same time increase controller Type just need to add an adapter , No need to change to Servlet The logic of , Comply with opening and closing principle .
This is the introduction of adapter mode , I hope to point out that .
Reference resources
《 Zen of design pattern 》
https://blog.csdn.net/wwwdc1012/article/details/82780560