策略模式配合java8的应用
在用java编写业务代码的过程中,经常会碰到一个业务有不同种的实现。典型的如用户登录,登录入口只有一个,但是要匹配微信、网易、QQ、支付宝、新浪微博等不同的登录渠道。各种业务场景的具体实现又各不相同,有的实现细节业务非常复杂。如果不合理的编码,会导致代码观感很差,影响阅读和维护。今天以这个场景来探讨下策略模式配合java8如何实现优雅编码,代码如下:
1、定义登录请求对象,具体参数不做过多探讨,这里只标识登录的渠道码
public class LogingRequest {
private String loginTypeCode;
/** 其他业务参数 **/
public String getLoginTypeCode() {
return loginTypeCode;
}
public void setLoginTypeCode(String loginTypeCode) {
this.loginTypeCode = loginTypeCode;
}
}
2、一般程序员可能不加思索,按业务逻辑就开始编码,代码应该是这样的
// 普通程序员的写法
public void loginWithIfElse(LogingRequest logingRequest) {
if ("wechat".equals(logingRequest.getLoginTypeCode())) {
// 微信登录的逻辑,
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从微信渠道登录");
} else if ("qq".equals(logingRequest.getLoginTypeCode())) {
// qq登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从QQ渠道登录");
} else if ("netease".equals(logingRequest.getLoginTypeCode())) {
// 网易登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从网易渠道登录");
} else if ("sina".equals(logingRequest.getLoginTypeCode())) {
// 新浪微博登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从新浪微博渠道登录");
} else if ("alipay".equals(logingRequest.getLoginTypeCode())) {
// 支付宝登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从支付宝渠道登录");
}
}
这样写出来的代码很长,很难看理解,考虑到各登录渠道里还有很复杂的逻辑,也会有很多if+esle,眼睛都会看花,到时候估计不光别人维护你代码会骂娘,你自己看的都一头大。
3、有经验的程序员会抽取一个公共的接口,不同的登录渠道在实现接口后,在自己类中维护和登录逻辑,代码如下
public interface LoginService {
void login(LogingRequest logingRequest);
}
public class WeChatLoginService implements LoginService {
public void login(LogingRequest logingRequest) {
/**一大堆逻辑
* $$$$$&^&^&^&%&%&&^&^&^&
* erwerewrwrewr
* 2343243242
*/
System.out.println("从微信渠道登录");
}
}
public class QQLoginService implements LoginService {
public void login(LogingRequest logingRequest) {
/**一大堆逻辑
* $$$$$&^&^&^&%&%&&^&^&^&
* erwerewrwrewr
* 2343243242
*/
System.out.println("从QQ渠道登录");
}
}
public class NeteaseLoginService implements LoginService {
public void login(LogingRequest logingRequest) {
/**一大堆逻辑
* $$$$$&^&^&^&%&%&&^&^&^&
* erwerewrwrewr
* 2343243242
*/
System.out.println("从网易渠道登录");
}
}
public class SinaLoginService implements LoginService {
public void login(LogingRequest logingRequest) {
/**一大堆逻辑
* $$$$$&^&^&^&%&%&&^&^&^&
* erwerewrwrewr
* 2343243242
*/
System.out.println("从新浪微博渠道登录");
}
}
public class AlipayLoginService implements LoginService {
public void login(LogingRequest logingRequest) {
/**一大堆逻辑
* $$$$$&^&^&^&%&%&&^&^&^&
* erwerewrwrewr
* 2343243242
*/
System.out.println("从支付宝渠道登录");
}
}
// 把具体实现分接口实现
public void loginWithInterface(LogingRequest logingRequest) {
if ("wechat".equals(logingRequest.getLoginTypeCode())) {
new WeChatLoginService().login(logingRequest);
} else if ("qq".equals(logingRequest.getLoginTypeCode())) {
new QQLoginService().login(logingRequest);
} else if ("netease".equals(logingRequest.getLoginTypeCode())) {
new NeteaseLoginService().login(logingRequest);
} else if ("sina".equals(logingRequest.getLoginTypeCode())) {
new SinaLoginService().login(logingRequest);
} else if ("alipay".equals(logingRequest.getLoginTypeCode())) {
new AlipayLoginService().login(logingRequest);
}
}
4、除了这,你还是不喜欢这么多if+else,怎么办,接下来就是我要说的策略模式,建立一个枚举来维护各接口实现,并实现策略路由
public enum LoginTypeEnum {
WECHAT("wechat", WeChatLoginService::new, "微信登录"), QQ("qq", QQLoginService::new, "qq登录"),
NETEASE("netease", NeteaseLoginService::new, "网易登录"), SINA("sina", SinaLoginService::new, "微博登录"),
ALIPAY("alipay", AlipayLoginService::new, "支付宝登录");
private String code;
private Supplier<LoginService> loginService;
private String desc;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
private LoginTypeEnum(String code, Supplier<LoginService> loginService, String desc) {
this.code = code;
this.loginService = loginService;
this.desc = desc;
}
public Supplier<LoginService> getLoginService() {
return loginService;
}
public void setLoginService(Supplier<LoginService> loginService) {
this.loginService = loginService;
}
public static LoginTypeEnum getByLoginTypeCode(String loginTypeCode) {
return Stream.of(LoginTypeEnum.values()).filter(x -> x.getCode().equals(loginTypeCode)).findAny()
.orElseThrow(() -> new RuntimeException("登录类型编码错误"));
}
}
5、最后的业务类,三种方式的写法
public class LoginServiceBiz {
// 普通程序员的写法
public void loginWithIfElse(LogingRequest logingRequest) {
if ("wechat".equals(logingRequest.getLoginTypeCode())) {
// 微信登录的逻辑,
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从微信渠道登录");
} else if ("qq".equals(logingRequest.getLoginTypeCode())) {
// qq登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从QQ渠道登录");
} else if ("netease".equals(logingRequest.getLoginTypeCode())) {
// 网易登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从网易渠道登录");
} else if ("sina".equals(logingRequest.getLoginTypeCode())) {
// 新浪微博登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从新浪微博渠道登录");
} else if ("alipay".equals(logingRequest.getLoginTypeCode())) {
// 支付宝登录的逻辑
/**
* 一大堆逻辑 $$$$$&^&^&^&%&%&&^&^&^& erwerewrwrewr 2343243242
*/
System.out.println("从支付宝渠道登录");
}
}
// 把具体实现分接口实现
public void loginWithInterface(LogingRequest logingRequest) {
if ("wechat".equals(logingRequest.getLoginTypeCode())) {
new WeChatLoginService().login(logingRequest);
} else if ("qq".equals(logingRequest.getLoginTypeCode())) {
new QQLoginService().login(logingRequest);
} else if ("netease".equals(logingRequest.getLoginTypeCode())) {
new NeteaseLoginService().login(logingRequest);
} else if ("sina".equals(logingRequest.getLoginTypeCode())) {
new SinaLoginService().login(logingRequest);
} else if ("alipay".equals(logingRequest.getLoginTypeCode())) {
new AlipayLoginService().login(logingRequest);
}
}
// 采用java8配置策略模式实现登录自动路由到具体实现方法上
public void loginWithJava8(LogingRequest logingRequest) {
LoginTypeEnum.getByLoginTypeCode(logingRequest.getLoginTypeCode()).getLoginService().get().login(logingRequest);
}
6、测试结果
public // 测试类
class Test {
public static void main(String[] args) {
LoginServiceBiz loginServiceBiz = new LoginServiceBiz();
LogingRequest logingRequest = new LogingRequest();
logingRequest.setLoginTypeCode("wechat");
System.out.println("=======用最普通的写法开始登录=========");
loginServiceBiz.loginWithIfElse(logingRequest);
System.out.println("=======用最普通的写法登录成功=========");
System.out.println();
System.out.println("=======用接口分离的写法开始登录=========");
loginServiceBiz.loginWithInterface(logingRequest);
System.out.println("=======用接口分离的写法登录成功=========");
System.out.println();
System.out.println("=======用策略模式java8的写法开始登录=========");
loginServiceBiz.loginWithJava8(logingRequest);
System.out.println("=======用策略模式java8写法登录成功=========");
}
}
执行结果:
=======用最普通的写法开始登录=========
从微信渠道登录
=======用最普通的写法登录成功=========
=======用接口分离的写法开始登录=========
从微信渠道登录
=======用接口分离的写法登录成功=========
=======用策略模式java8的写法开始登录=========
从微信渠道登录
=======用策略模式java8写法登录成功=========