Design Pattern Study Notes (8) Introduction to Adapter Pattern and Its Application

Adapter mode (Adapter) refers to the interface of a class into another compatible interface. For example, the adapters in our daily life and the universal chargers used in ancient times are equivalent to the adapter mode used in the program.

1. Introduction to Adapter Mode

1.1 Structure of Adapter Pattern

The adapter pattern pattern is mainly divided into two types: class structure pattern and object structure pattern:

1.1.1 Class Adapter Pattern

The class adapter pattern matches one interface to another through multiple inheritance. For some object-oriented languages ​​such as C# and Java that do not support multiple inheritance, then we can inherit a class and implement multiple interfaces at the same time to achieve the effect of an adapter. As shown below:

  • Adaptee: Adapter class, which is the component that needs to be accessed and adapted
  • Target: Target interface, the interface used by the current system business, which can be an abstract class or an interface
  • Adapter: Adapter class, by inheriting and implementing the target interface, let the client access the adapter according to the method of the target interface
  • Client: client, consumer of the adapter

1.1.2 Object Adapter Pattern

The difference between the object adapter pattern and the class adapter is that the coupling between the adapter class and the adapter class in the object adapter is lower. As shown below:

  • Adaptee: Adapter class, which is the component that needs to be accessed and adapted
  • Target: Target interface, the interface used by the current system business, which can be an abstract class or an interface
  • Adapter: The adapter class, through aggregation and realization of the target interface, allows the client to access the adapter according to the method of the target interface
  • Client: client, consumer of the adapter

1.2 Application Implementation of Adapter Mode

We can implement it according to the above two modes:

1.2.1 Class Adapter Implementation Code

//适配者类
public class Adaptee {
    public void specificRequest(){
        System.out.println("我是适配者类");
    }
}
//目标接口
public interface Target {
    public void request();
}
//适配器类
public class Adapter extends Adaptee implements Target{
    @Override
    public void request() {
        specificRequest();
    }
}
//客户端类
public class Client {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.request();
    }
}

1.2.2 Object adapter implementation code

//适配者类
public class Adaptee {
    public void specificRequest(){
        System.out.println("我是适配者类");
    }
}
//对象适配器类
public class ObjectAdapter implements Target{

    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
//客户端类
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

We found that the object adapter pattern introduces the adapter in the adapter class, so that the two classes are connected together by means of aggregation. According to the design principle, aggregation takes precedence over inheritance, so in our daily use, we should choose more object adapter patterns.

3. Adapter application scenarios

3.1 Log adaptation application in MyBatis

The typical representative in MyBatis is the log module, for example, it is adapted to the log types of slf4j, Apache Commons Logging, Log4j2and JDK loggingetc. Let’s take a look at the specific implementation:

//统一的Log接口
public interface Log {
  boolean isDebugEnabled();
  boolean isTraceEnabled();
  void error(String s, Throwable e);
  void error(String s);
  void debug(String s);
  void trace(String s);
  void warn(String s);
}

MyBatis defines adapters for multiple log types, taking Log4j2the implementation as an example:

public class Log4j2Impl implements Log {

  private final Log log;

  public Log4j2Impl(String clazz) {
    Logger logger = LogManager.getLogger(clazz);
    if (logger instanceof AbstractLogger) {
      log = new Log4j2AbstractLoggerImpl((AbstractLogger) logger);
    } else {
      log = new Log4j2LoggerImpl(logger);
    }
  }

  @Override
  public boolean isDebugEnabled() {
    return log.isDebugEnabled();
  }

  @Override
  public boolean isTraceEnabled() {
    return log.isTraceEnabled();
  }

  @Override
  public void error(String s, Throwable e) {
    log.error(s, e);
  }

  @Override
  public void error(String s) {
    log.error(s);
  }

  @Override
  public void debug(String s) {
    log.debug(s);
  }

  @Override
  public void trace(String s) {
    log.trace(s);
  }

  @Override
  public void warn(String s) {
    log.warn(s);
  }
}

So after the project is added Log4j2, it can be used directly to print MyBatis log information.

3.2 Adaptation and application of various MQ messages or interfaces in the marketing system

3.2.1 Code Engineering Introduction

In the marketing system, the system will receive various MQ messages or interfaces, such as messages for inviting users, internal orders, and external orders. At this time, the adapter mode can be used to adapt these MQ messages. As shown below:

The code directory structure is as follows:

src
 ├─main
 │  ├─java
 │  │  └─cn
 │  │      └─ethan
 │  │          └─design
 │  │              │  OrderAdapterService.java
 │  │              │
 │  │              ├─adapter
 │  │              │      MQAdapter.java
 │  │              │      RebateInfo.java
 │  │              │
 │  │              ├─impl
 │  │              │      InsideOrderService.java
 │  │              │      POPOrderAdapterService.java
 │  │              │
 │  │              ├─mq
 │  │              │      create_account.java
 │  │              │      OrderMq.java
 │  │              │      POPOrderDelivered.java
 │  │              │
 │  │              └─service
 │  │                      OrderService.java
 │  │                      POPOrderService.java
 │  │
 │  └─resources
 └─test
      └─java
              ApiTest.java
  • The mq and service directories are MQ message types and services provided
  • The adapter directory contains the adapted MQ message body and some attribute information
  • The service directory is a simulated interface adaptation

3.2.2 Code implementation

  1. MQ message body and attribute information adaptation
//MQ属性信息适配
public class RebateInfo {

    private String userId;
    private String bizId;
    private Date bizTime;
    private String desc;
}
//MQ消息体适配,将不同MQ的各种属性,映射成我们需要的属性并返回
public class MQAdapter {

    public static RebateInfo filter(String strJson, Map<String, String> link) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return filter(JSON.parseObject(strJson, Map.class), link);
    }

    public static RebateInfo filter(Map obj, Map<String, String> link) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        RebateInfo rebateInfo = new RebateInfo();
        for (String key : link.keySet()) {
            Object val = obj.get(link.get(key));
            RebateInfo.class.getMethod("set" + key.substring(0, 1).toUpperCase() + key.substring(1), String.class).invoke(rebateInfo, val.toString());
        }
        return rebateInfo;
    }
}
  1. Interface Service Adaptation

Two interfaces are provided, one is to directly judge whether it is the first order, and the other needs to judge according to the order quantity. Define a unified adapter interface:

//统一适配接口
public interface OrderAdapterService {

    boolean isFirst(String uId);
}
//内部商品接口
public class InsideOrderService implements OrderAdapterService {

    private OrderService orderService = new OrderService();

    @Override
    public boolean isFirst(String uId) {
        return orderService.queryUserOrderCount(uId) <= 1;
    }
}
//第三方商品接口
public class POPOrderAdapterService implements OrderAdapterService {

    private POPOrderService popOrderService = new POPOrderService();

    @Override
    public boolean isFirst(String uId) {
        return popOrderService.isFirstOrder(uId);
    }
}

final test

public class ApiTest {

    @Test
    public void test_MQAdapter() throws ParseException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = simpleDateFormat.parse("2022-3-29 23:09:17");

        create_account create_account = new create_account();
        create_account.setNumber("100001");
        create_account.setAddress("河北省.廊坊市.广阳区.大学里职业技术学院");
        create_account.setAccountDate(parse);
        create_account.setDesc("在校开户");

        HashMap<String, String> link01 = new HashMap<>();
        link01.put("userId", "number");
        link01.put("bizId", "number");
        link01.put("bizTime", "accountDate");
        link01.put("desc", "desc");
        RebateInfo rebateInfo01 = MQAdapter.filter(create_account.toString(), link01);
        System.out.println("mq.create_account(适配前)" + create_account.toString());
        System.out.println("mq.create_account(适配后)" + JSON.toJSONString(rebateInfo01));

        OrderMq orderMq = new OrderMq();
        orderMq.setUid("100001");
        orderMq.setSku("10928092093111123");
        orderMq.setOrderId("100000890193847111");
        orderMq.setCreateOrderTime(parse);

        HashMap<String, String> link02 = new HashMap<String, String>();
        link02.put("userId", "uid");
        link02.put("bizId", "orderId");
        link02.put("bizTime", "createOrderTime");
        RebateInfo rebateInfo02 = MQAdapter.filter(orderMq.toString(), link02);
        System.out.println("mq.orderMq(适配前)" + orderMq.toString());
        System.out.println("mq.orderMq(适配后)" + JSON.toJSONString(rebateInfo02));
    }

    @Test
    public void test_itfAdapter() {
        OrderAdapterService popOrderAdapterService = new POPOrderAdapterService();
        System.out.println("判断首单,接口适配(POP):" + popOrderAdapterService.isFirst("100001"));

        OrderAdapterService insideOrderService = new InsideOrderService();
        System.out.println("判断首单,接口适配(自营):" + insideOrderService.isFirst("100001"));
    }

}

The test results are as follows:

mq.create_account(适配前){"accountDate":1648566557000,"address":"河北省.廊坊市.广阳区.大学里职业技术学院","desc":"在校开户","number":"100001"}
mq.create_account(适配后){"bizId":"100001","bizTime":1591077840669,"desc":"在校开户","userId":"100001"}
mq.orderMq(适配前){"createOrderTime":1648566557000,"orderId":"100000890193847111","sku":"10928092093111123","uid":"100001"}
mq.orderMq(适配后){"bizId":"100000890193847111","bizTime":1591077840669,"userId":"100001"}
---------------------------------------------------------------------------------
13:12:20.335 [main] INFO  c.e.design.service.POPOrderService - POP商家,查询⽤户的订单是否为⾸单:100001
判断首单,接口适配(POP):true
13:12:20.339 [main] INFO  cn.ethan.design.service.OrderService - 自营商家,查询用户的订单是否为首单:100001
判断首单,接口适配(自营):false

Guess you like

Origin blog.csdn.net/weixin_45536242/article/details/125767120