策略模板模式
1.策略模式的本质
策略模式的本质:分离算法,选择实现。
纵观整个策略模式实现的功能和设计,它的本质还是“分离算法,选择实现”,因为分离并封装了算法,才能够很容易地修改和添加算法;也能很容易地动态切换使用不同的算法,也就是动态选择一个算法来实现需要的功能。
策略模式的本质是将算法的定义、选择和使用分离,使得它们可以独立变化。在策略模式中,将具体的算法封装成独立的策略类,使得这些策略类可以相互替换,而不影响使用它们的客户端代码。
2.何时选用策略模式
建议在以下情况中选用策略模式。
-
当一个系统需要在多个算法中选择一种合适的算法时,可以考虑使用策略模式。通过将每个算法封装成独立的策略类,可以在运行时动态地选择和切换算法,而不需要修改客户端代码。
-
当一个类有多个相关的行为,而这些行为在不同的情况下需要不同的实现时,可以考虑使用策略模式。每个行为可以封装成一个具体的策略类,客户端根据需要选择合适的策略类进行调用。
3.优缺点
策略模式有以下优点。
-
策略模式实现了算法的定义、选择和使用的分离。通过将不同的算法封装成独立的策略类,使得算法可以独立变化,而不影响使用算法的客户端代码。这提高了代码的灵活性和可维护性。
-
策略模式遵循开闭原则。通过添加新的策略类,可以方便地扩展系统的功能,而不需要修改现有的代码。这使得系统更具可扩展性和可复用性。
-
策略模式可以减少条件语句的使用。不同的算法被封装在独立的策略类中,客户端只需要选择合适的策略类进行调用,而不需要使用大量的条件语句来判断不同的算法。
-
策略模式可以方便地切换算法。由于算法被封装在独立的策略类中,可以在运行时动态地选择和切换算法,而不需要修改客户端代码。这使得系统更具灵活性和适应性。
策略模式有以下缺点。
-
策略模式增加了系统中的类和对象数量。每个具体策略类都需要一个单独的类进行实现,这可能会增加系统的复杂性。
-
客户端需要了解不同的策略类,并选择合适的策略类进行调用。这增加了客户端的复杂性,特别是当策略类的数量较多时。
-
策略模式将算法的选择推迟到客户端,可能导致客户端代码变得复杂。客户端需要根据具体的条件选择合适的策略类,这可能涉及到较多的条件判断逻辑。
4.策略模式的结构
-
环境类(Context):它持有一个策略类的引用,通过调用策略类的方法来执行具体的算法。环境类提供了一个统一的接口,使得客户端可以方便地使用不同的策略。
-
抽象策略类(Strategy):它定义了一个公共接口,用于封装具体的算法。不同的具体策略类实现这个接口,提供了不同的算法实现。
-
具体策略类(Concrete Strategy):它实现了抽象策略类定义的算法接口,具体实现了具体的算法逻辑。
5.实现
支付案例
策略模式在工作中使用,一下就能想到的就是支付
模拟支付宝、微信、银联支付
1.支付策略及其实现类
/**
* @description:支付策略接口
*/
public interface PayStrategy {
/**
* 支付方法
* @param orderId 订单id
* @param amount 金额
* @return
*/
boolean pay(String orderId, Long amount);
}
/**
* @description:微信支付策略
*/
public class WxPay implements PayStrategy{
@Override
public boolean pay(String orderId, Long amount) {
System.out.println("调用微信支付策略-->订单id:"+orderId+" ,金额:"+amount);
return true;
}
}
/**
* @description:支付宝支付策略
*/
public class ZfbPay implements PayStrategy{
@Override
public boolean pay(String orderId, Long amount) {
System.out.println("调用支付宝支付策略-->订单id:"+orderId+" ,金额:"+amount);
return true;
}
}
/**
* @description:银联支付策略
*/
public class YlPay implements PayStrategy{
@Override
public boolean pay(String orderId, Long amount) {
System.out.println("调用银联支付策略-->订单id:"+orderId+" ,金额:"+amount);
return true;
}
}
2.支付上下文类
/**
* @description:支付上下文类
*/
public class PayContext {
/**
* 订单id
*/
private String orderId;
/**
* 金额
*/
private Long amount;
private PayStrategy payStrategy;
public PayContext(String orderId, Long amount, PayStrategy payStrategy) {
this.orderId = orderId;
this.amount = amount;
this.payStrategy = payStrategy;
}
public void payContext(){
//调用具体策略的支付
this.payStrategy.pay(orderId,amount);
}
}
3.测试类
public class Client {
public static void main(String[] args) {
//微信支付
new PayContext("10001",100L,new WxPay()).payContext();
//支付宝支付
new PayContext("10002",200L,new ZfbPay()).payContext();
//银联支付
new PayContext("10003",300L,new YlPay()).payContext();
}
}
4.结果
看起来好像没有上下文什么事情,但是如果没有上下文,那么就需要客户端来直接与具体的策略交互,尤其是当需要提供一些公共功能,或者是相关状态存储的时候,会大大增加客户端使用的难度。因此,引入上下文还是很必要的,有了上下文,这些工作就由上下文来完成了,客户端只需要与上下文交互就可以了,这样会让整个设计模式更独立、更有整体性,也让客户端更简单。
支付案例参数不一致问题
实际使用各种支付时,各自的参数必然不一样,但是策略又是接口定义好的,那应该怎么办呢,这时介于客户端和策略方法中间的上下文类就发挥作用了,可以在这里面搞点小动作,把微信和支付宝用到的参数声明在这里,然后把自己传给策略类,不同的策略类需要什么参数就取什么参数
1.策略类及其实现类
/**
* @description:支付策略接口
*/
public interface PayStrategy {
/**
* 支付方法
* @return
*/
boolean pay(PayContext payContext);
}
/**
* @description:微信支付策略
*/
public class WxPay implements PayStrategy{
@Override
public boolean pay(PayContext payContext) {
System.out.println("微信支付参数:"+payContext.getWxAppserect());
System.out.println("调用微信支付策略-->订单id:"+payContext.getOrderId()+" ,金额:"+payContext.getAmount());
return true;
}
}
/**
* @description:支付宝支付策略
*/
public class ZfbPay implements PayStrategy{
@Override
public boolean pay(PayContext payContext) {
System.out.println("支付宝支付参数:"+payContext.getZfbId());
System.out.println("调用支付宝支付策略-->订单id:"+payContext.getOrderId()+" ,金额:"+payContext.getAmount());
return true;
}
}
/**
* @description:银联支付策略
*/
public class YlPay implements PayStrategy{
@Override
public boolean pay(PayContext payContext) {
System.out.println("银联支付没有参数");
System.out.println("调用银联支付策略-->订单id:"+payContext.getOrderId()+" ,金额:"+payContext.getAmount());
return true;
}
}
2.支付上下文类
/**
* @description:支付上下文类
*/
@Getter
public class PayContext {
/**
* 订单id
*/
private String orderId;
/**
* 金额
*/
private Long amount;
/**
* 微信支付需要的参数
*/
private String wxAppserect;
/**
* 支付宝支付需要的参数
*/
private String zfbId;
private PayStrategy payStrategy;
public PayContext(String orderId, Long amount, String wxAppserect, String zfbId, PayStrategy payStrategy) {
this.orderId = orderId;
this.amount = amount;
this.wxAppserect = wxAppserect;
this.zfbId = zfbId;
this.payStrategy = payStrategy;
}
public void payContext(){
//调用具体策略的支付
this.payStrategy.pay(this);
}
}
3.测试类
public class Client {
public static void main(String[] args) {
//微信支付
PayContext wxPay = new PayContext("10001", 100L, "wx123", "", new WxPay());
wxPay.payContext();
//支付宝支付
PayContext zfbPay = new PayContext("10001", 100L, "", "zfb123", new ZfbPay());
zfbPay.payContext();
//银联支付
PayContext ylPay = new PayContext("10001", 100L, "", "", new YlPay());
ylPay.payContext();
}
}
4.结果