策略模式
推荐阅读:策略设计模式
示例
假设有一个支付系统,需要支持使用不同的支付方式(策略),我们可以抽象出一个策略接口,然后定义具体的策略类来实现该接口。
策略接口:
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}
的内容替换为其他值,也就是说可能会有不同的策略,此时只需要创建新的策略对象,并将其注入到上下文中使用即可。