为什么需要使用到设计模式:
使用设计模式可以重构整体架构代码,可以使代码提高复用性,扩展性,减少代码冗余问题。
什么是策略模式:
策略模式是对算法的包装,是把使用算法的责任和算法本身分隔开来,委派给不同的对象管理,最终可以实现解决多重if判断问题:
为什么叫策略模式:
每个if判断都可以理解为就是一个策略。
public String toPay(String payCode){
if(payCode.equals("ali_pay")){
return "调用支付宝接口支付";
}
if(payCode.equals("weixin_pay")){
return "调用微信支付接口支付";
}
if(payCode.equals("yinlian_pay")){
return "调用银联支付接口支付";
}
return "未找到该支付接口";
}
我们来看上面一段代码,我们传不同的payCode,得到对应的支付平台,调用接口行为是相同的,调用接口代码是不同的,
我们来用策略模式实现下:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或者抽象类实现,此角色给出所有的具体策略类所需的接口。
具体策略(ConcreStrategy)角色:包装了相关的算法或行为。
定义策略接口-》实现不同的策略类-》利用多态或其他方式调用策略。
我们来创建共同的行为:
public interface PayStrategy {
/**
* 共同方法行为
* @return
*/
public String toPay();
}
具体策略实现:
public class AliPayStrategy implements PayStrategy {
@Override
public String toPay()
return "调用支付宝接口。。。。。";
}
}
public class WeXinPayStrategy implements PayStrategy {
@Override
public String toPay() {
return "调用微信支付接口。。。。。";
}
}
public class XiaoMiPayStrategy implements PayStrategy {
@Override
public String toPay() {
return "调用小米支付接口。。。。。";
}
}
策略枚举类 所有策略的具体实现:
public enum PayEnumStrategy {
/**
* 支付宝支付
*/
ALI_PAY("com.zigao.com.strategy.impl.AliPayStrategy"),
/**
* 微信支付
*/
WEICHAT_PAY("com.zigao.com.strategy.impl.WeXinPayStrategy"),
/**
* 小米支付
*/
XIAOMI_PAY("com.zigao.com.strategy.impl.XiaoMiPayStrategy");
/**
* 完整地址
*/
private String className;
PayEnumStrategy(String className) {
this.className = className;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
使用策略工厂获取具体测虐实现:
public class StrateFactory {
public static PayStrategy getPayStrategy(String strategyType){
try {
//1:获取枚举类中classname
String classname = PayEnumStrategy.valueOf(strategyType).getClassName();
//2:使用java反射技术初始化类
return (PayStrategy)Class.forName(classname).newInstance();
}catch (Exception e){
return null;
}
}
}
使用Context上下文获取具体策略实现:
@Component
public class PayContextStrategy {
/**
* 获取具体策略实现
*/
public String toPayHtml(String payCode){
//判断是否为空
if(StringUtils.isEmpty(payCode)){
return "payCode======>>>>>不能为空";
}
//使用策略工厂获取具体策略实现
PayStrategy payStrategy = StrateFactory.getPayStrategy(payCode);
if(payStrategy == null){
return "没有找到具体策略实现。。。。。";
}
return payStrategy.toPay();
}
}
总代代码实现完了,我们来测试下:
@RestController
@RequestMapping("/pay")
public class PayController{
//打印日志
public Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private PayContextStrategy payContextStrategy;
@PostMapping("/toPay")
public ResponseMessage upload(@RequestBody Map map) {
ResponseMessage responseMessage = new ResponseMessage(0);
try {
String payCode = (String) map.get("payCode");
String payHtml = payContextStrategy.toPayHtml(payCode);
responseMessage.setMessage(payHtml);
} catch (Exception e) {
logger.error("调用支付异常,", e);
throw new RuntimeException(e.getMessage());
}
return responseMessage;
}
}
上面虽然实现了,但是还是不完美,我们用另一种方式实现。
通过bean对象注入的方式实现:
<bean id = "weXinPayStrategy" class = “com.zigao.com.strategy.impl.WeXinPayStrategy”>
使用类名小写名称 从Spring容器中获取具体策略对象;
这些可以放到数据库中
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for payment
-- ----------------------------
DROP TABLE IF EXISTS `payment`;
CREATE TABLE `payment` (
`id` int(10) NOT NULL,
`channel_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`channel_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`strategy_bean_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of payment
-- ----------------------------
INSERT INTO `payment` VALUES (1, '支付宝支付实现', 'ALI_PAY', 'aliPayStrategy');
INSERT INTO `payment` VALUES (2, '微信宝支付实现', 'WEICHAT_PAY', 'weXinPayStrategy');
INSERT INTO `payment` VALUES (3, '小米宝支付实现', 'XIAOMI_PAY', 'xiaoMiPayStrategy');
SET FOREIGN_KEY_CHECKS = 1;