某天早上,Skr郎正在一边悠哉的吃着加了三个鸡蛋的手抓饼,一边悠闲地逛着论坛,看着沙雕网友的帖子,Skr郎会心一笑,正欲给沙雕帖子点赞,邮件忽的弹出,Skr郎慢悠悠的打开邮件
任务: 对接阿里支付接口
时限: 一周
要求如下:
1. 单笔限额不超过1W
2. 可以成功提现
3. 发起提现后,可以主动查询提现结果
Skr郎心中暗喜,看我两天搞定,剩下的时间就可以嘿嘿嘿了
/**
* 阿里业务处理
*
* @author gp6
* @date 2020/3/13
*/
public class AlibabaHandler {
void singleQuota() {
System.out.println("阿里校验单笔限额");
}
void pay() {
System.out.println("阿里支付逻辑");
}
void getResult() {
System.out.println("阿里主动查询支付结果");
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 支付接口(第一个方法)
AlibabaHandler alibabaHandler = new AlibabaHandler();
alibabaHandler.singleQuota();
alibabaHandler.pay();
// 查询接口(第二个方法)
AlibabaHandler alibabaHandler1 = new AlibabaHandler();
alibabaHandler1.getResult();
}
}
Skr郎看着完成的代码,心中评价道:这段代码,逻辑严谨,注释清晰,优雅中透露着洒脱,洒脱中透露着不羁,完美!
正洋洋自得间,项目经理喊道:Skr郎,你过来一下!Skr郎赶紧屁颠屁颠的跑过去.
项目经理:临时加个需求,把微信支付也接进来,根据前台传的渠道,使用不同的支付方式,时间不加.
Skr郎:好的,没问题(MMP)
/**
* 微信业务处理
*
* @author gp6
* @date 2020/3/13
*/
public class WechatHandler {
void singleQuota() {
System.out.println("微信校验单笔限额");
}
void pay() {
System.out.println("微信支付逻辑");
}
void getResult() {
System.out.println("微信主动查询支付结果");
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 前台传的渠道 1:阿里 2:微信
String channel = "1";
// 支付逻辑(第一个方法)
if ("1".equals(channel)) {
// 阿里支付接口
AlibabaHandler alibabaHandler = new AlibabaHandler();
alibabaHandler.singleQuota();
alibabaHandler.pay();
} else if ("2".equals(channel)) {
// 微信支付接口
WechatHandler wechatHandler = new WechatHandler();
wechatHandler.singleQuota();
wechatHandler.pay();
}
// 查询接口(第二个方法)
if ("1".equals(channel)) {
// 阿里查询
AlibabaHandler alibabaHandler = new AlibabaHandler();
alibabaHandler.getResult();
} else if ("2".equals(channel)) {
// 微信查询
WechatHandler wechatHandler = new WechatHandler();
wechatHandler.getResult();
}
}
}
Skr郎看着完成的代码,心中评价道:这段代码,逻辑严谨,注释清晰,优雅中透露着洒脱,洒脱中透露着不羁,虽然没有上一版优雅,但还是比较不错的!
正洋洋自得间,又听项目经理喊道:Skr郎,你过来一下!Skr郎心里想着如果这次加需求不加时间,老子坚决不做!
项目经理:临时在加个需求,把通联和Ping++支付也接进来,根据前台传的渠道,使用不同的支付方式,时间不加.
Skr郎:好的,没问题(心里问候一下他的族中长辈)
/**
* Ping++业务处理
*
* @author gp6
* @date 2020/3/13
*/
public class PingHandler {
void singleQuota() {
System.out.println("Ping++校验单笔限额");
}
void pay() {
System.out.println("Ping++支付逻辑");
}
void getResult() {
System.out.println("Ping++主动查询支付结果");
}
}
/**
* 通联业务处理
*
* @author gp6
* @date 2020/3/13
*/
public class AllinpayHandler {
void singleQuota() {
System.out.println("通联校验单笔限额");
}
void pay() {
System.out.println("通联支付逻辑");
}
void getResult() {
System.out.println("通联主动查询支付结果");
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 前台传的渠道 1:阿里 2:微信 3:Ping++ 4:通联
String channel = "1";
// 支付逻辑(第一个方法)
if ("1".equals(channel)) {
// 阿里支付接口
AlibabaHandler alibabaHandler = new AlibabaHandler();
alibabaHandler.singleQuota();
alibabaHandler.pay();
} else if ("2".equals(channel)) {
// 微信支付接口
WechatHandler wechatHandler = new WechatHandler();
wechatHandler.singleQuota();
wechatHandler.pay();
}else if ("3".equals(channel)) {
// Ping++支付接口
PingHandler pingHandler = new PingHandler();
pingHandler.singleQuota();
pingHandler.pay();
}else if ("4".equals(channel)) {
// 通联支付接口
AllinpayHandler allinpayHandler = new AllinpayHandler();
allinpayHandler.singleQuota();
allinpayHandler.pay();
}
// 查询接口(第二个方法)
if ("1".equals(channel)) {
// 阿里查询
AlibabaHandler alibabaHandler = new AlibabaHandler();
alibabaHandler.getResult();
} else if ("2".equals(channel)) {
// 微信查询
WechatHandler wechatHandler = new WechatHandler();
wechatHandler.getResult();
}else if ("3".equals(channel)) {
// Ping++查询
PingHandler pingHandler = new PingHandler();
pingHandler.getResult();
}else if ("4".equals(channel)) {
// 通联查询
AllinpayHandler allinpayHandler = new AllinpayHandler();
allinpayHandler.getResult();
}
}
}
Skr郎看着完成的代码,心中评价道:这段代码,逻辑严谨,注释清晰…我呸,这写的什么鬼东西!看着长长的if else,Skr郎陷入沉思…
如果后面再加新的渠道,是不是每次都要改动PayService中的调用逻辑,而且如果有别的方法要用此段逻辑,if else 又要复制一遍
脑中过滤着以往所学的设计模式…突然,灵光一闪,策略模式
定义:
定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户
看了策略模式的定义,是不是很符合这种场景
定义了一系列算法(支付逻辑),并将每个算法(支付逻辑)封装起来,使它们可以相互替换(根据不同channel切换不同的支付逻辑),且算法的变化不会影响使用算法的客户(PayService)
简直完美,Skr郎沾沾自喜
/**
* 支付的抽象策略类
* 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现
*
* @author gp6
* @date 2020/3/13
*/
public interface PayHandler {
/**
* 单笔限额
*/
void singleQuota();
/**
* 支付
*/
void pay();
/**
* 提现结果查询
*/
void getResult();
}
/**
* 微信业务处理
* 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现
*
* @author gp6
* @date 2020/3/13
*/
public class WechatHandler implements PayHandler {
public void singleQuota() {
System.out.println("微信校验单笔限额");
}
public void pay() {
System.out.println("微信支付逻辑");
}
public void getResult() {
System.out.println("微信主动查询支付结果");
}
}
/**
* 阿里业务处理
* 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现
*
* @author gp6
* @date 2020/3/13
*/
public class AlibabaHandler implements PayHandler {
public void singleQuota() {
System.out.println("阿里校验单笔限额");
}
public void pay() {
System.out.println("阿里支付逻辑");
}
public void getResult() {
System.out.println("阿里主动查询支付结果");
}
}
通联与Ping++代码类似
/**
* 环境(Context)类:持有一个策略类的引用,最终给客户端调用
*
* @author gp6
* @date 2020/3/13
*/
public class Context {
private PayHandler payHandler;
public Context(PayHandler payHandler){
this.payHandler = payHandler;
}
/**
* 单笔限额
*/
void singleQuota() {
payHandler.singleQuota();
}
/**
* 支付
*/
void pay() {
payHandler.pay();
}
/**
* 提现结果查询
*/
void getResult() {
payHandler.getResult();
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 前台传的渠道 1:阿里 2:微信 3:Ping++ 4:通联
Integer channel = 1;
// 支付逻辑(第一个方法)
Context context;
switch (channel) {
case 1:
context = new Context(new AlibabaHandler());
break;
case 2:
context = new Context(new WechatHandler());
break;
case 3:
context = new Context(new PingHandler());
break;
case 4:
context = new Context(new AllinpayHandler());
break;
default:
throw new RuntimeException("渠道不支持!");
}
context.singleQuota();
context.pay();
// 查询接口(第二个方法)
Context context2;
switch (channel) {
case 1:
context2 = new Context(new AlibabaHandler());
break;
case 2:
context2 = new Context(new WechatHandler());
break;
case 3:
context2 = new Context(new PingHandler());
break;
case 4:
context2 = new Context(new AllinpayHandler());
break;
default:
throw new RuntimeException("渠道不支持!");
}
context2.getResult();
}
}
使用了策略模式,但是调用者(PayService)中,还是有重复的大量的if else
根据不用的渠道创建不同的具体策略类(new AlibabaHandler()),这不是典型的工厂模式吗…
将工厂模式放入策略环境中
/**
* 环境(Context)类:持有一个策略类的引用,最终给客户端调用
*
* @author gp6
* @date 2020/3/13
*/
public class Context {
private PayHandler payHandler;
public Context(Integer channel){
switch (channel) {
case 1:
payHandler = new AlibabaHandler();
break;
case 2:
payHandler = new WechatHandler();
break;
case 3:
payHandler = new PingHandler();
break;
case 4:
payHandler = new AllinpayHandler();
break;
default:
throw new RuntimeException("渠道不支持!");
}
}
/**
* 单笔限额
*/
void singleQuota() {
payHandler.singleQuota();
}
/**
* 支付
*/
void pay() {
payHandler.pay();
}
/**
* 提现结果查询
*/
void getResult() {
payHandler.getResult();
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 前台传的渠道 1:阿里 2:微信 3:Ping++ 4:通联
Integer channel = 1;
// 支付逻辑(第一个方法)
Context context = new Context(channel);
context.singleQuota();
context.pay();
// 查询接口(第二个方法)
Context context2 = new Context(channel);
context2.getResult();
}
}
此时如果再添加渠道,只需在Context的构造方法的判断逻辑中添加新的渠道,然后在相应的支付逻辑类中写入相应逻辑,只在策略环境中存在if else,调用者无需写重复的if else
switch (channel) {
case 1:
payHandler = new AlibabaHandler();
break;
case 2:
payHandler = new WechatHandler();
break;
case 3:
payHandler = new PingHandler();
break;
case 4:
payHandler = new AllinpayHandler();
break;
// 新的渠道
case 5:
payHandler = new XXXHandler();
break;
default:
throw new RuntimeException("渠道不支持!");
}
/**
* 新渠道的业务逻辑处理
* 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现
*
* @author gp6
* @date 2020/3/13
*/
public class XXXHandler implements PayHandler{
.....
}
写到此处Skr郎欣喜的点点头,暗自得意,正打算将代码提交,忽然眉头一皱,每次添加新的渠道,都要修改判断逻辑,不是违背了 开闭原则 吗
Skr再次沉思
/**
* 环境(Context)类:持有一个策略类的引用,最终给客户端调用
*
* @author gp6
* @date 2020/3/13
*/
public class Context {
private PayHandler payHandler;
public Context(PayEnum payEnum){
try {
payHandler= (PayHandler) Class.forName(payEnum.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException("渠道错误!");
}
}
/**
* 单笔限额
*/
void singleQuota() {
payHandler.singleQuota();
}
/**
* 支付
*/
void pay() {
payHandler.pay();
}
/**
* 提现结果查询
*/
void getResult() {
payHandler.getResult();
}
}
/**
* 策略枚举
*
* @author gp6
* @date 2020/3/13
*/
public enum PayEnum {
/**
* 渠道对应类全路径
*/
OPERATION_ADD("com.gp6.pay.AlibabaHandler", 1),
OPERATION_SUB("com.gp6.pay.WechatHandler", 2),
OPERATION_MUL("com.gp6.pay.PingHandler", 3);
PayEnum(String className, Integer channel) {
this.className = className;
this.channel = channel;
}
/**
* 类的全路径
*/
private String className;
/**
* 渠道
*/
private Integer channel;
/**
* 匹配渠道
*
* @param channel 渠道
* @return 相关枚举
*/
public static PayEnum matchChannel(Integer channel) {
for (PayEnum payEnum : PayEnum.values()) {
if (payEnum.getChannel().equals(channel)) {
return payEnum;
}
}
throw new RuntimeException("渠道不支持!");
}
public String getClassName() {
return className;
}
public Integer getChannel() {
return channel;
}
}
/**
* 支付服务类
*
* @author gp6
* @date 2020/3/13
*/
public class PayService {
public static void main(String[] args) {
// 前台传的渠道 1:阿里 2:微信 3:Ping++ 4:通联
Integer channel = 1;
// 支付逻辑(第一个方法)
Context context = new Context(PayEnum.matchChannel(channel));
context.singleQuota();
context.pay();
// 查询接口(第二个方法)
Context context2 = new Context(PayEnum.matchChannel(channel));
context2.getResult();
}
}
此时,如果想添加通联的渠道只需在PayEnum中添加
OPERATION_MUL("com.gp6.pay.AllinpayHandler", 4)
然后在com.gp6.pay.AllinpayHandler中撰写相应逻辑即可
Skr郎写到此处,心满意足的点点头,心中评价道:这段代码,逻辑严谨,注释清晰,优雅中透露着洒脱,洒脱中透露着不羁,真是"此码只应天上有,人间难得几回寻!"
呀! 想不到我作诗的功夫也如此深厚,哎,如此完美的男人,别人只能羡慕嫉妒恨!
StrategyContext相当于文章中的Context
StrategyOperation相当于文章中的PayHandle
StrategyOperationAdd与StrategyOperationMul相当于文章中的AlibabaHandler/AllinpayHandler/PingHandler/WechatHandler