从实际项目中学设计模式:策略模式与模板模式的应用
也许有非常多的人都有这样的疑问,明明看了很多设计模式的书,看的时候感觉每个设计模式也都能看懂,但是就是用不起来,而一旦不用起来,过一阵又都忘得差不多了,下次又得重新学。如果你总是停留在学的这个阶段,而不去真正用起来,往往都会往复的循环。所以说要想学好设计模式,关键还是在于用。
至于如何去用,效果最好的还是从自己实际的项目中去找场景,设计模式就是解决某一类问题套路,你需要思考的问题就是项目中有哪些场景存在着和这个模式类似的问题,一旦发现了同样的问题,我们要做的就是套用模式而已,而只要你用设计模式解决了项目场景中的问题,那么对于你来说这套设计模式就已经掌握了。
也许你一开始实在想不到项目中哪些地方可以应用对应的设计模式,那么我来帮你,在这里我将会对我们项目常见的功能,进行设计模式的分析和应用,我们不再是对概念抽丝剥茧,而是从实实在在的项目功能中去应用设计模式,从中感受到设计模式给我的程序带来的简洁和扩展性,从熟悉的地方去应用设计模式,那么你想不掌握都难。
从"登录功能"中发现问题。
用户登录这个功能我想凡是学过编程的人对这个功能都不会陌生,也正是因为这个大家熟知的功能,我们挑这个功能进行重构会使大家对设计模式理解得更透彻,而且理解之后也能切实的应用起来,然后在项目中结合类似的场景真的把“策略模式”和“模板模式”用得熟练和巧妙。
首先我们简单的了解功能需求:
当然项目最初期的功能往往很简单,产品经理要求不高,只做了下面几个要求:
1、可以通过用户名密码、手机号验证码两种方式登录系统。
2、登录失败次数不能超过5次,超过5次的话就锁定账户30分钟。
3、已经禁用的用户不能登录系统。
于是你开始干活了:
好了听到这个需求后,这就是一个简单的需求,想想不过就是提供2个不同的登录方法,然后根据不同的登录类型调用不同的登录方式就行了,于是你拿起键盘就开始写代码了,于是乎你的代码也许就和下面类似。
1、控制层代码如下,根据不同的登录方式调用不同的服务层方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class LoginController{
@Autowired
private LoginService loginService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(String username, String content, int loginType) {
Result result=null;
if(loginType==1){
//密码登录
result= loginService.loginByPassword(username,content);
}else if(loginType==2){
//手机验证码登录
result=loginService.loginBySMS(username,content);
}
return result;
}
}
2、服务层提供两种登录方式,并对登录业务逻辑进行处理:
public interface LoginService {
/**
* 密码登录
* @return
*/
Result loginByPassword(String userName, String password);
/**
* 短信验证码登录
* @return
*/
Result loginBySMS(String username, String smsCode);
}
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private userDao userDao;
@Override
public Result loginByPassword(String userName, String password) {
//查询用户信息
UserInfo userInfo=userDao.queryByUserName(userName);
if(userInfo==null){
return new Result("001","用户不存在",null);
}
//检查用户是否被禁用了(0正常,1禁用)
if(userInfo.getStatus()==1){
return new Result("002","账号已被禁用",null);
}
//检查用户是否被锁定了。
Date lockEndTime=userInfo.getLockEndTime();
if(lockEndTime!=null&&lockEndTime.getTime()>System.currentTimeMillis()){
return new Result("003","账户已锁定",null);
}
//验证密码是否正确
if(!userInfo.getPassword().equals(password)){
//密码错误后,累计登录错误次数
userInfo.setFailNumber(userInfo.getFailNumber()+1);
//检查登录错误次数是否超过5次,超过则锁定账户30分钟。
if(userInfo.getFailNumber()>5){
Date locTime= DateUtils.addMinutes(new Date(),30);
userInfo.setLockEndTime(locTime);
}
userDao.update(userInfo);
return new Result("004","账户名或密码错误",null);
}
//密码正确后返回用户信息和登录的token
return new Result("200","成功","生成的token");
}
@Override
public Result loginBySMS(String username, String smsCode) {
//查询用户信息
UserInfo userInfo=userDao.queryByUserName(username);
if(userInfo==null){
return new Result