Java多态的定义我就不说了,今天用用户登录的案例来讲解多态。
用户登录功能是交互系统中的必不可少的一个功能。
登录方式有以下几种
- 用户名+密码
- 用户名+验证码
- 手机号+密码
- 手机号+验证码
数据传输的格式是:
public class LoginUser {
private String username; // 用户名
private String password; // 密码
private String mobile; // 手机号
private String code; // 验证码
// 忽略getter setter
}
- if判断的方式
使用if判断是最简单也是最容易想到的方式,按照步骤一步一步的操作,这是一种面向过程的思维(本人对面向过程,面向对象,函数式编程没有偏见,他们都是为了解决问题的)。这种方式如果判断条件少时,阅读起来通俗易懂;但是,条件多时,就不那么好阅读了。
if (Objects.nonNull(user.getUsername()) && Objects
.nonNull(user.getPassword())) {
// 用户名+密码
User user1 = userService.findByUsername(user.getUsername());
if (Objects.equals(user1.getPassword(), user.getPassword())) {
return user1;
}
throw new RuntimeException("密码不正确");
} else if (Objects.nonNull(user.getUsername()) && Objects
.nonNull(user.getCode())) {
// 用户名+验证码
User user1 = userService.findByUsername(user.getUsername());
if (codeService.codeCheck(user.getCode())) {
return user1;
}
throw new RuntimeException("验证码不正确");
} else if (Objects.nonNull(user.getMobile()) && Objects
.nonNull(user.getPassword())) {
// 手机号+密码
User user1 = userService.findByMobile(user.getMobile());
if (Objects.equals(user1.getPassword(), user.getPassword())) {
return user1;
}
throw new RuntimeException("密码不正确");
} else if (Objects.nonNull(user.getMobile()) && Objects
.nonNull(user.getCode())) {
// 手机号+验证码
User user1 = userService.findByMobile(user.getMobile());
if (codeService.codeCheck(user.getCode())) {
return user1;
}
throw new RuntimeException("验证码不正确");
} else {
throw new RuntimeException("组合不正确");
}
2. 判定表的方式
判定表的方式是对if判断的一个改善,不再使用if判断,而是使用类似于条件矩阵的方式来判定,好处是当条件比较多时,也容易阅读(一般一个函数中的代码不要超过40行,这样的话,可以在一屏中全部阅读整个函数,对于阅读者更加容易掌控理解)。
判定表源码:https://github.com/wenyu7980/decisiontable
public class DecisionTableLoginHandler implements LoginHandler {
private final DecisionTable<Function<LoginUser, User>> DECISIONS = DecisionTable
.of();
@Autowired
private UserService userService;
@Autowired
private CodeService codeService;
public DecisionTableLoginHandler() {
// 用户名 手机号 密码 验证码
DECISIONS.add(this::userPasswd, NOT_NULL(), ANY(), NOT_NULL(), ANY());
DECISIONS.add(this::userCode, NOT_NULL(), NULL(), NULL(), NOT_NULL());
DECISIONS
.add(this::mobilePasswd, NULL(), NOT_NULL(), NOT_NULL(), ANY());
DECISIONS.add(this::mobileCode, NULL(), NOT_NULL(), NULL(), NOT_NULL());
}
@Override
public User login(LoginUser user) {
Function<LoginUser, User> function = DECISIONS
.get(user.getUsername(), user.getMobile(), user.getPassword(),
user.getCode())
.orElseThrow(() -> new RuntimeException("组合不正确"));
return function.apply(user);
}
private User userPasswd(LoginUser user) {
// 用户名+密码
User user1 = userService.findByUsername(user.getUsername());
if (Objects.equals(user1.getPassword(), user.getPassword())) {
return user1;
}
throw new RuntimeException("密码不正确");
}
private User userCode(LoginUser user) {
// 用户名+验证码
User user1 = userService.findByUsername(user.getUsername());
if (codeService.codeCheck(user.getCode())) {
return user1;
}
throw new RuntimeException("验证码不正确");
}
private User mobilePasswd(LoginUser user) {
// 手机号+密码
User user1 = userService.findByMobile(user.getMobile());
if (Objects.equals(user1.getPassword(), user.getPassword())) {
return user1;
}
throw new RuntimeException("密码不正确");
}
private User mobileCode(LoginUser user) {
// 手机号+验证码
User user1 = userService.findByMobile(user.getMobile());
if (codeService.codeCheck(user.getCode())) {
return user1;
}
throw new RuntimeException("验证码不正确");
}
}
3.面向接口的方式
这种方式是把判定表和面向接口编程进行整合,好处是,条件和业务是内聚到一个文件中,如果需要增减条件判断情况,只需要增减接口实现类就行,不要更改其他文件,使逻辑解耦(高内聚,低耦合)。但是缺点也很明显,如果对这种结构不了解的话,阅读起来会很费劲。
public interface LoginComponent {
User login(LoginUser user);
default Decision username() {
return NULL();
}
default Decision password() {
return NULL();
}
default Decision mobile() {
return NULL();
}
default Decision code() {
return NULL();
}
}
以上三种方式。
总结:
三种方式没有优劣,看情境而定。逻辑简单用if,变更大用面向接口。
代码:
wenyu7980/UserLoginSample