0 x0, introduction

🤡 weekend tour failure, king of the new season, 😍 addicted to yun-yin, chewing section “Beauty of Design Patterns” pressure fine, this paper corresponding design patterns and paradigms: structural type (51), Adapter Pattern (Adapter Pattern).

Understand the definition, application scenarios, class adapters, and object adapters

Tips: Secondary knowledge processing inevitably has mistakes, interested in the time can refer to the original, thank you.


0 x1, definition

Adapter, easy to understand, such as the computer power adapter at hand, its role is to convert 220V home AC to 20V DC, and for example, apple notebook computer, only lightning port, if you want to use USB keyboard and mouse/network cable, you need an expansion dock/adapter.

The adapter pattern converts incompatible interfaces into compatible interfaces so that classes that would otherwise not work together because of incompatible interfaces can work together.

To put it simply:

Two classes that don’t have much to do with each other and want to do something with each other, it’s a little tedious to change their interfaces. An intermediate class can be added to coordinate the relationship between the two classes to complete the related business.

Applicable scenario

  • Encapsulate defective interface design (such as dependent external system has defects in interface design, isolation of defects, and secondary encapsulation of the interface);
  • Unify the interface design of multiple classes (the realization of a function depends on multiple external systems, and the interface is adapted to a unified interface definition, multiplexing);
  • Replace dependent external systems;
  • Compatible with older versions of interfaces (the interfaces to be deprecated are not deleted directly, but remain deprecated for the time being, and the internal implementation logic is delegated to the new interface implementation);
  • Adapt to different formats of data; (e.g. Java arrays.aslist () converts array-type data to a collection type);
  • Different interface protocol conversion;

0x2, Class adapter

According to the different relationship between adapter class and adapter class, it can be divided into class adapter and object adapter. The former is implemented by inheritance relation, and the latter is implemented by combination relation.

Write a simple translation conversion example ~

// Interface to be adapted
public class English {
    void speakEnglish(String talk) {
        System.out.println("[English]+ talk); }}// Target interface
interface Chinese {
    void speakChinese(String talk);
}

// Adapter role
public class ClassTranslator extends English implements Chinese {
    @Override
    public void speakChinese(String talk) {
        // The parent method can be called or overridden directly
        super.speakEnglish(talk);
        System.out.println("Pretend to request translation interface, output translation result: [英 文] Macabaca"); }}// Test case
public class AdapterTest {
    public static void main(String[] args) {
        Chinese translator = new ClassTranslator();
        translator.speakChinese("Ma ka ba ka"); }}Copy the code

The output is as follows:

The UML class diagram is as follows:

Roles are as follows:

  • Target (Target interface) → the interface expected by the customer, the Target is interface;
  • Adaptee → also called Adaptee class;
  • Adapter → inherit Adapter class, implement target interface, rewrite, call method as needed;

0x3 object Adapter

Create a new object adapter class:

public class ObjectAdapter implements Chinese {
    private English english;

    public ObjectAdapter(English english) {
        this.english = english;
    }

    @Override
    public void speakChinese(String talk) {
        english.speakEnglish(talk);
        System.out.println("Pretend to request translation interface, output translation result: [英 文] Macabaca"); }}// Test case
public static void main(String[] args) {
    Chinese translator = new ObjectAdapter(new English());
    translator.speakChinese("Ma ka ba ka");
}
Copy the code

The output is the same as above, and the difference is not hard to see from the code:

Object adapters support the incoming adapter object, can flexibly achieve a variety of adapter interface adaptation, while class adapters inherit directly, cannot be dynamically modified (Java does not support multiple inheritance), so object adapters are usually used more.

The UML class diagram is as follows:

Roles are as follows:

  • Target → desired interface, which can be a concrete or abstract class or interface;
  • Adaptee → also called Adaptee class;
  • Adapter → Wrap an object that needs to be adapted and convert the original interface into the target interface;

0x4 single interface adapter mode

Also known as the default adapter pattern, the target interface has multiple methods, an abstract class implements the interface, overrides each method to provide a default implementation (empty method), and subclasses override the parent method as needed.

For example, there are many types of Chinese, such as Mandarin, Cantonese, Chaoshan, Hakka, Shanghainese, etc., but now we just need to convert to Mandarin:

interface ChineseTarget {
    void speakChinese(String talk); / / mandarin
    void speakCantonese(String talk);   / / cantonese
    void speakChiuchow(String talk);    / / teochew
    void speakHakka(String talk);   / / hakka
}

public abstract class BaseAdapter implements ChineseTarget {
    @Override public void speakChinese(String talk) {}@Override public void speakCantonese(String talk) {}@Override public void speakChiuchow(String talk) {}@Override public void speakHakka(String talk) {}}public class CantoneseTranslator extends BaseAdapter {
    private English english;

    public CantoneseTranslator(English english) { this.english = english; }

    @Override public void speakCantonese(String talk) {
        english.speakEnglish(talk);
        System.out.println("Pretend to request a translation interface and output the translation result: [Cantonese] Macabaka"); }}// Test case
public static void main(String[] args) {
    BaseAdapter translator = new CantoneseTranslator(new English());
    translator.speakCantonese("Ma ka ba ka");
}
Copy the code

The output is as follows:

Finally, the advantages and disadvantages of the adapter pattern are discussed.

  • The target class is decoupled from the adapter class, and the adaptor class is referenced to reuse the existing adaptor class without modifying the original structure.
  • The transparency and reusability of the class are increased, and the specific business implementation is encapsulated in the adapter class, and the modification of the adapter class only affects the adapter class.
  • Flexibility and scalability is very good, you can easily replace adapter classes, can match multiple different adapter classes and subclasses to the same target class;
  • Comply with OCP principle and Richter’s replacement principle (LSP);

Disadvantages:

  • Excessive nesting will lead to interface overcrowding. The function of one target class will affect the whole adaptation chain.
  • The target interface depends on too many adaptation interfaces. Modifying the target interface will cause all adaptation interfaces to be customized.
  • In Java, the target abstract class of a class adapter can only be an interface, and the adapter class cannot be final (cannot inherit).

0x4. Extra Meal: Comparison of four structural design modes

The code structure of these four patterns is so similar that, broadly speaking, they can all be referred to as Wrapper mode, which rewraps the original class with the Wrapper class. But their intent is completely different (problem solved, application scenario), and the differences are briefly described below.

  • Proxy mode: Defines a proxy class for the original class without changing its interface. The main purpose is to control access, not enforce it. This is the biggest difference from the decorator mode.
  • Bridge pattern: Solves the class explosion problem caused by the breadth of class inheritance by separating the interface part from the implementation part so that they can be changed easily and independently.
  • Decorator mode: solve the problem of class explosion caused by the depth of class inheritance, enhance the function without changing the original class interface, and support the use of multiple decorators nested.
  • Adapter pattern: an after-the-fact strategy to convert between different interface functions.