Adapter Pattern)
Before the formal start, let's first think about a few questions: if the existing new project can use a lot of legacy code in the old project, are you planning to finish the new project from the beginning or understand the module functions and interfaces of the old project? If you have learned about the legacy code and find that several important functional module interfaces are different (because they may come from multiple old projects) and cannot be reused directly, are you planning to stop using the legacy code? If you do not want to give up (this should be correct, after all, the correctness of the legacy code is verified by practice), can you only rewrite the remaining n-1 interface, even rewrite all n interfaces? If this is not done, is there any simple method? 1. What is the adapter mode? First, we need to know what the adapter is. Well, I have heard of the laptop power adapter? It is amazing to switch the v ac power to the 15 v dc power needed by the notebook. A small power adapter solves the problem of mismatch between the household power and the notebook power type? Yes, we neither change the household power (change it to 15 v dc) nor change the notebook (change it to v ac ), but we did solve this problem ------- adapter mode -- design mode used to implement conversion between different interfaces II. for example, assume that we have two encapsulated functional modules, but they require different parameters (although the parameters are essentially the same object). For example, our module A (Text check module) yes: package AdapterPattern;/*** @ author ayqy * text check module (similar to "spelling and syntax check" in MSOffice Word) */public class TextCheckModule {FormatText text; public TextCheckModule (FormatText text) {this. text = text;}/** omit many specific Check operations .. */} The entry to module A requires A FormatText parameter, which is defined as follows: package AdapterPattern; /*** @ author ayqy * defines the formatted text */public interface FormatText {String text = null;/*** @ return the number of logical lines of text */public abstract int getLineNumber (); /*** @ param index row number * @ return content of the index row */public abstract String getLine (int index ); /** omit other useful methods */} There is also Module B (text display module), which is like this: package AdapterPattern; /*** @ author ayqy * text display module */public class Tex TPrintModule {DefaultText text; public TextPrintModule (DefaultText text) {this. text = text;}/** omitted many DefaultText: package AdapterPattern required for display-related operations **/} Module B entry; /*** @ author ayqy * defines the default text */public interface DefaultText {String text = null;/*** @ return the number of logical lines of text */public abstract int getLineCount (); /*** @ param index row number * @ return content of the index row */public abstract String getLineContent (int index );/* * Omit other useful methods */} our new project requires A Text Processing Program (like MSOffice Word). We need to call module A to implement the text check function, we also need to call Module B to implement the text display function, but the problem is that the interfaces of the two modules do not match, so we cannot directly reuse the ready-made A and B .. In this case, we only have two options: Modify FormatText (or DefaultText) to meet defatext text (or FormatText), and modify the internal implementation of A (or B) to define the third interface MyText, modify A and B so that they can use MyText as parameters to unify the interfaces. Of course, we may prefer the first one. After all, we need less modifications, but even so, the workload is still very large. We need to open the encapsulation of A, understand its internal implementation, and modify the method call details ------- in fact, we still have A better choice-define an Adapter, converts FormatText to DefaultText (or vice versa): package AdapterPattern;/*** @ author ayqy * defines the default text adapter */public class DefaultTextAdapter implements DefaultText {FormatText forma TText = null; // source object/*** @ param text the source text object to be converted */public DefaultTextAdapter (FormatText formatText) {this. formatText = formatText ;}@ Override public int getLineCount () {int lineNumber; lineNumber = formatText. getLineNumber ();/** add additional Conversion Processing here **/return lineNumber;} @ Override public String getLineContent (int index) {String line; line = formatText. getLine (index);/** add additional Conversion Processing here **/return l Ine ;}} our practice is actually quite simple: define the Adapter to implement the target interface to obtain and retain each method in the source interface object to implement the Target Interface (call the method of the source interface object in the method body and add additional processing to implement the conversion) what should I do if the adapter is ready? Implement a Test class to Test: package AdapterPattern; /*** @ author ayqy * Test interface adapter */public class Test implements FormatText {public static void main (String [] args) {// create the source interface object FormatText text = new Test (); // create a text check module object TextCheckModule tcm = new TextCheckModule (text ); /* Call tcm for text check * // create an adapter object and convert the source interface object to the Target Interface object. defatexttextadapter textAdapter = new DefaultTextAdapter (text ); // use the Adapter to create the TextPrintModule object Tpm = new TextPrintModule (textAdapter);/* Call tcm to display text */}/*. Ignore the lazy section below .. * // @ Override public int getLineNumber () {// TODO Auto-generated method stub return 0;} @ Override public String getLine (int index) {// TODO Auto-generated method stub return null;} (P.S. forgive me for my laziness. Who makes FormatText an interface ..) Of course, Test does not have any running results, but compilation is enough to indicate that our conversion is correct .. ------- In fact, we ignore a very important issue. In this example, the methods of the source interface and the Target Interface correspond to each other, in other words: methods defined in the source interface have similar methods in the target interface. Of course, this situation is rare, there are usually non-corresponding methods (the source interface contains methods not defined by the target interface, or the opposite). At this time, we have two options: throw an exception, however, you should make a detailed description in the comments or documents, as shown in the following figure: 1 throw new UnsupportedOperationException (); // The source interface does not support this operation to complete an empty implementation, for example, return false, 0, null, and so on, depending on the specific scenario, each has its own advantages, and cannot be generalized. in another adapter implementation method example, we use the method of "holding the source interface object and implementing the Target Interface" to implement the adapter, in fact, there is another way -- Multi-inheritance (or multiple interfaces). If an Adapter class implements both the interface and the B interface, there is no doubt that Adapte R object belongs to both A and B (the principle of multi-inheritance is similar ..) Although Java does not support multi-inheritance, in a language environment that supports multi-inheritance, we should think of this implementation method and decide whether to use multi-inheritance to implement Adapter. to sum up, when we hold a two-hole plug and a three-hole plug at the same time, we are always used to turning the plug core into an octal shape. Why not buy an adapter? There is no need to damage the plug or the plug-in port (sometimes code modification is indeed destructive, so we can avoid modification and damage). What's more important is: we can lend the purchased adapter to a friend (reusable) package AdapterPattern;/*** @ author ayqy * Text check module (similar to the "spelling and syntax check" in MSOffice Word ") */public class TextCheckModule {FormatText text; public TextCheckModule (FormatText text) {this. text = text;}/** omit many specific Check operations .. */} The entry to module A requires A FormatText parameter, which is defined as follows: package AdapterPattern; /*** @ author ayqy * defines the formatted text */public interface FormatText {String text = null;/*** @ return the number of logical lines of text */public abstract int getLineNumber (); /*** @ param index row number * @ return content of the index row */public abstract String getLine (int index ); /** omit other useful methods */} There is also Module B (text display module), which is like this: package AdapterPattern; /*** @ author ayqy * text display module */public class Tex TPrintModule {DefaultText text; public TextPrintModule (DefaultText text) {this. text = text;}/** omitted many DefaultText: package AdapterPattern required for display-related operations **/} Module B entry; /*** @ author ayqy * defines the default text */public interface DefaultText {String text = null;/*** @ return the number of logical lines of text */public abstract int getLineCount (); /*** @ param index row number * @ return content of the index row */public abstract String getLineContent (int index );/* * Omit other useful methods */} our new project requires A Text Processing Program (like MSOffice Word). We need to call module A to implement the text check function, we also need to call Module B to implement the text display function, but the problem is that the interfaces of the two modules do not match, so we cannot directly reuse the ready-made A and B .. In this case, we only have two options: Modify FormatText (or DefaultText) to meet defatext text (or FormatText), and modify the internal implementation of A (or B) to define the third interface MyText, modify A and B so that they can use MyText as parameters to unify the interfaces. Of course, we may prefer the first one. After all, we need less modifications, but even so, the workload is still very large. We need to open the encapsulation of A, understand its internal implementation, and modify the method call details ------- in fact, we still have A better choice-define an Adapter, converts FormatText to DefaultText (or vice versa): package AdapterPattern;/*** @ author ayqy * defines the default text adapter */public class DefaultTextAdapter implements DefaultText {FormatText forma TText = null; // source object/*** @ param text the source text object to be converted */public DefaultTextAdapter (FormatText formatText) {this. formatText = formatText ;}@ Override public int getLineCount () {int lineNumber; lineNumber = formatText. getLineNumber ();/** add additional Conversion Processing here **/return lineNumber;} @ Override public String getLineContent (int index) {String line; line = formatText. getLine (index);/** add additional Conversion Processing here **/return l Ine ;}} our practice is actually quite simple: define the Adapter to implement the target interface to obtain and retain each method in the source interface object to implement the Target Interface (call the method of the source interface object in the method body and add additional processing to implement the conversion) what should I do if the adapter is ready? Implement a Test class to Test: package AdapterPattern; /*** @ author ayqy * Test interface adapter */public class Test implements FormatText {public static void main (String [] args) {// create the source interface object FormatText text = new Test (); // create a text check module object TextCheckModule tcm = new TextCheckModule (text ); /* Call tcm for text check * // create an adapter object and convert the source interface object to the Target Interface object. defatexttextadapter textAdapter = new DefaultTextAdapter (text ); // use the Adapter to create the TextPrintModule object Tpm = new TextPrintModule (textAdapter);/* Call tcm to display text */}/*. Ignore the lazy section below .. * // @ Override public int getLineNumber () {// TODO Auto-generated method stub return 0;} @ Override public String getLine (int index) {// TODO Auto-generated method stub return null;} (P.S. forgive me for my laziness. Who makes FormatText an interface ..) Of course, Test does not have any running results, but compilation is enough to indicate that our conversion is correct .. ------- In fact, we ignore a very important issue. In this example, the methods of the source interface and the Target Interface correspond to each other, in other words: methods defined in the source interface have similar methods in the target interface. Of course, this situation is rare, there are usually non-corresponding methods (the source interface contains methods not defined by the target interface, or the opposite). At this time, we have two options: throw an exception, however, you should make a detailed description in the comments or documents, as shown in the following figure: 1 throw new UnsupportedOperationException (); // The source interface does not support this operation to complete an empty implementation, for example, return false, 0, null, and so on, depending on the specific scenario, each has its own advantages, and cannot be generalized. in another adapter implementation method example, we use the method of "holding the source interface object and implementing the Target Interface" to implement the adapter, in fact, there is another way -- Multi-inheritance (or multiple interfaces). If an Adapter class implements both the interface and the B interface, there is no doubt that Adapte R object belongs to both A and B (the principle of multi-inheritance is similar ..) Although Java does not support multi-inheritance, in a language environment that supports multi-inheritance, we should think of this implementation method and decide whether to use multi-inheritance to implement Adapter. to sum up, when we hold a two-hole plug and a three-hole plug at the same time, we are always used to turning the plug core into an octal shape. Why not buy an adapter? There is no need to damage the plug or the plug-in port (sometimes code modification is indeed destructive, so we can avoid modification and damage). What's more important is: we can lend the purchased adapter to a friend (reusable)