策略模式

推荐阅读:策略设计模式

示例

假设有一个支付系统,需要支持使用不同的支付方式(策略),我们可以抽象出一个策略接口,然后定义具体的策略类来实现该接口。

策略接口

public interface PaymentStrategy {
    void pay(int amount);
}

具体策略

public class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("Using Credit Card to pay: " + amount);
    }
}

public class PayPalPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("Using PayPal to pay: " + amount);
    }
}

使用策略模式,我们可以轻松地切换支付方式,而无需修改其他代码。方法就是创建一个上下文对象,并将不同的策略对象注入到上下文中:

上下文

public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(int amount) {
        paymentStrategy.pay(amount);
    }
}

而客户端代码只需要调用上下文对象的 checkout 方法,并根据需要设置不同的策略对象即可:

ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Using Credit Card to pay: 100

cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(200); // Using PayPal to pay: 200

这样不仅能够轻松地切换支付方式,而且如果需要加入新的支付方式,只需创建新的策略对象并注入到上下文中,而不需要修改其他代码。

在 MyBatis 中的应用

MyBatis 中有一个 GenericTokenParser 类,它用于解析字符串中的占位符:

public class GenericTokenParser {

  private final String openToken;
  private final String closeToken;
  private final TokenHandler handler;

  public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
    this.openToken = openToken;
    this.closeToken = closeToken;
    this.handler = handler;
  }

  public String parse(String text) {
    // ...
    builder.append(handler.handleToken(expression.toString()));
    // ...
  }
}

可以看到它的构造方法接收三个参数,openToken 和 closeToken 分别是占位符开始和结束的标记,而 handler 是一个 TokenHandler 对象。

TokenHandler 是一个接口,它只有一个 handleToken 方法,用于返回占位符需要被替换为的值:

public interface TokenHandler {
  String handleToken(String content);
}

例如,ParameterMappingTokenHandler 是一个实现该接口的类,它的返回值是?

@Override
public String handleToken(String content) {
  parameterMappings.add(buildParameterMapping(content));
  return "?";
}

所以下面的语句用来将类似于#{id}的内容替换为?

ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
String sql = parser.parse(originalSql);

在这里,TokenHandler 就是策略接口,ParameterMappingTokenHandler 就是具体的策略,GenericTokenParser 就是上下文。

我们可能希望将#{id}的内容替换为其他值,也就是说可能会有不同的策略,此时只需要创建新的策略对象,并将其注入到上下文中使用即可。

posted @ 2024-12-08 15:42  Higurashi-kagome  阅读(1)  评论(0编辑  收藏  举报