原始代码

业务层UserService

@Service
public class UserService {

    public LoginResp login(LoginReq loginReq){

        if(loginReq.getType().equals("account")){
            System.out.println("用户名密码登录");

            //执行用户密码登录逻辑

            return new LoginResp();

        }else if(loginReq.getType().equals("sms")){
            System.out.println("手机号验证码登录");

            //执行手机号验证码登录逻辑

            return new LoginResp();
        }else if (loginReq.getType().equals("we_chat")){
            System.out.println("微信登录");

            //执行用户微信登录逻辑

            return new LoginResp();
        }
        LoginResp loginResp = new LoginResp();
        loginResp.setSuccess(false);
        System.out.println("登录失败");
        return loginResp;
    }
}

注意:我们重点讲的是设计模式,并不是登录的逻辑,所以以上代码并没有真正的实现登录功能

问题分析

  • 业务层代码大量使用到了if...else,在后期阅读代码的时候会非常不友好,大量使用if...else性能也不高
  • 如果业务发生变更,比如现在新增了QQ登录方式,这个时候需要修改业务层代码,违反了开闭原则

解决:

使用工厂方法设计模式+策略模式解决

改进代码

要将上述代码改为使用工厂模式和策略模式,首先我们需要定义几个关键元素:策略接口、具体策略类、策略工厂以及修改UserService来使用这些策略。下面是改造后的代码示例:

1. 定义策略接口

public interface LoginStrategy {
    LoginResp login(LoginReq loginReq);
}

2. 创建具体策略类

AccountLoginStrategy

@Service
public class AccountLoginStrategy implements LoginStrategy {
    @Override
    public LoginResp login(LoginReq loginReq) {
        System.out.println("用户名密码登录");
        // 执行用户密码登录逻辑
        return new LoginResp();
    }
}

SmsLoginStrategy

@Service
public class SmsLoginStrategy implements LoginStrategy {
    @Override
    public LoginResp login(LoginReq loginReq) {
        System.out.println("手机号验证码登录");
        // 执行手机号验证码登录逻辑
        return new LoginResp();
    }
}

WeChatLoginStrategy

@Service
public class WeChatLoginStrategy implements LoginStrategy {
    @Override
    public LoginResp login(LoginReq loginReq) {
        System.out.println("微信登录");
        // 执行用户微信登录逻辑
        return new LoginResp();
    }
}

3. 实现策略工厂

@Service
public class LoginStrategyFactory {
    
    @Autowired
    private AccountLoginStrategy accountLoginStrategy;
    
    @Autowired
    private SmsLoginStrategy smsLoginStrategy;
    
    @Autowired
    private WeChatLoginStrategy weChatLoginStrategy;
    
    public LoginStrategy getLoginStrategy(String type) {
        switch (type) {
            case "account":
                return accountLoginStrategy;
            case "sms":
                return smsLoginStrategy;
            case "we_chat":
                return weChatLoginStrategy;
            default:
                throw new IllegalArgumentException("Invalid login type");
        }
    }
}

4. 修改UserService使用策略

@Service
public class UserService {

    @Autowired
    private LoginStrategyFactory loginStrategyFactory;

    public LoginResp login(LoginReq loginReq){
        LoginStrategy strategy = loginStrategyFactory.getLoginStrategy(loginReq.getType());
        if(strategy == null){
            LoginResp loginResp = new LoginResp();
            loginResp.setSuccess(false);
            System.out.println("登录失败: 无效的登录类型");
            return loginResp;
        }
        return strategy.login(loginReq);
    }
}

通过这种方式,UserService不再直接包含各种登录逻辑,而是通过策略工厂获取对应的策略对象来处理登录请求,这使得代码更加灵活和可扩展。如果需要添加新的登录方式,只需增加一个新的策略类并修改工厂类即可,无需修改UserService的逻辑。