概述
一、定义
策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
二、特点
策略模式的主要优点如下。
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
其主要缺点如下。
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类,增加维护难度。
三、结构
策略模式的主要角色如下。
- 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
四、实现
以基于 Spring Boot 的电商系统的支付方式为例,在购物支付时可以选择支付宝支付、微信支付、银联支付,此时可以应用我们的策略模式。
4.1 抽象策略类
package com.example.demo.designpattern.strategy.service;
import com.example.demo.designpattern.strategy.model.PayVO;
import com.example.demo.designpattern.strategy.model.Result;
/**
* 支付抽象策略
*/
public interface PayStrategy {
/**
* 支付
*
* @param vo 参数
* @return 结果
*/
Result<Object> pay(PayVO vo);
}
4.2 具体策略类
4.2.1 支付宝支付
package com.example.demo.designpattern.strategy.service.concrete;
import com.example.demo.designpattern.strategy.model.AliPayInfo;
import com.example.demo.designpattern.strategy.model.PayModeEnum;
import com.example.demo.designpattern.strategy.model.PayVO;
import com.example.demo.designpattern.strategy.model.Result;
import com.example.demo.designpattern.strategy.service.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AliPayStrategy implements PayStrategy {
@Override
public Result<Object> pay(PayVO vo) {
log.info("{},{}", vo.getOrderId(), PayModeEnum.ALI_PAY.description());
AliPayInfo payInfo = AliPayInfo.builder().outTradeNo("70501111111S001111119").tradeNo("2014112400001000340011111118").build();
return Result.builder().code(0).data(payInfo).build();
}
}
4.2.2 微信支付
package com.example.demo.designpattern.strategy.service.concrete;
import com.example.demo.designpattern.strategy.model.PayModeEnum;
import com.example.demo.designpattern.strategy.model.PayVO;
import com.example.demo.designpattern.strategy.model.Result;
import com.example.demo.designpattern.strategy.model.WechatPayInfo;
import com.example.demo.designpattern.strategy.service.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class WechatPayStrategy implements PayStrategy {
@Override
public Result<Object> pay(PayVO vo) {
log.info("{},{}", vo.getOrderId(), PayModeEnum.WECHAT_PAY.description());
WechatPayInfo payInfo = WechatPayInfo.builder().prepayId("123").tradeType("JSAPI").build();
return Result.builder().code(0).data(payInfo).build();
}
}
4.2.3 银联支付
package com.example.demo.designpattern.strategy.service.concrete;
import com.example.demo.designpattern.strategy.model.PayModeEnum;
import com.example.demo.designpattern.strategy.model.PayVO;
import com.example.demo.designpattern.strategy.model.Result;
import com.example.demo.designpattern.strategy.model.UnionPayInfo;
import com.example.demo.designpattern.strategy.service.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class UnionPayStrategy implements PayStrategy {
@Override
public Result<Object> pay(PayVO vo) {
log.info("{},{}", vo.getOrderId(), PayModeEnum.UNION_PAY.description());
UnionPayInfo payInfo = UnionPayInfo.builder().id("ch_L8qn10mLmr1GS8e5OODmHaL4").orderNo("123456789").build();
return Result.builder().code(0).data(payInfo).build();
}
}
4.3 环境类
package com.example.demo.designpattern.strategy.context;
import com.example.demo.designpattern.strategy.model.PayModeEnum;
import com.example.demo.designpattern.strategy.model.PayVO;
import com.example.demo.designpattern.strategy.service.PayStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.Map;
@Service
public class PayContext {
@Autowired
private Map<String, PayStrategy> payStrategyMap;
public Object pay(PayVO vo) {
PayModeEnum payModeEnum = PayModeEnum.getEnum(vo.getPayMode());
Assert.notNull(payModeEnum, "暂不支持该支付方式:" + vo.getPayMode());
PayStrategy payStrategy = payStrategyMap.get(payModeEnum.strategy());
Assert.notNull(payStrategy, "暂不支持该支付策略:" + payModeEnum.strategy());
return payStrategy.pay(vo);
}
}
说明:payStrategyMap 是借助于 Spring 自动注入方式得到所有具体策略,key默认为类名(首字母小写),value为对应实例。
4.4 接口调用
package com.example.demo.designpattern.strategy.controller;
import com.example.demo.designpattern.strategy.context.PayContext;
import com.example.demo.designpattern.strategy.model.PayVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cashier")
public class CashierController {
@Autowired
private PayContext payContext;
@PostMapping("/pay")
public Object pay(@RequestBody PayVO vo) {
return payContext.pay(vo);
}
}
4.5 支付方式与策略对应关系枚举
package com.example.demo.designpattern.strategy.model;
import java.util.Arrays;
/**
* 支付方式枚举
*/
public enum PayModeEnum {
/**
* 支付宝支付
*/
ALI_PAY("aliPayStrategy", "支付宝支付策略"),
/**
* 微信支付
*/
WECHAT_PAY("wechatPayStrategy", "微信支付策略"),
/**
* 银联支付
*/
UNION_PAY("unionPayStrategy", "银联支付策略");
private final String strategy;
private final String description;
public String strategy() {
return strategy;
}
public String description() {
return description;
}
PayModeEnum(String strategy, String description) {
this.strategy = strategy;
this.description = description;
}
public static PayModeEnum getEnum(String name) {
return Arrays.stream(PayModeEnum.values()).filter(value -> value.name().equals(name)).findAny().orElse(null);
}
}
4.6 其它关联类
package com.example.demo.designpattern.strategy.model;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
public class PayVO implements Serializable {
private String payMode;
private String orderId;
}
package com.example.demo.designpattern.strategy.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> implements Serializable {
private Integer code;
private T data;
private String message;
}
package com.example.demo.designpattern.strategy.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AliPayInfo implements Serializable {
private String outTradeNo;
private String tradeNo;
}
package com.example.demo.designpattern.strategy.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WechatPayInfo implements Serializable {
private String tradeType;
private String prepayId;
}
package com.example.demo.designpattern.strategy.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UnionPayInfo implements Serializable {
private String id;
private String orderNo;
}
4.5 运行结果
选择支付宝支付
选择微信支付
选择银联支付
五、总结
策略模式避免了if…else、switch…case等操作,业务职责更清晰,符合开闭原则。
最后
以上就是文艺硬币为你收集整理的实战设计模式之策略模式一、定义二、特点三、结构四、实现五、总结的全部内容,希望文章能够帮你解决实战设计模式之策略模式一、定义二、特点三、结构四、实现五、总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复