栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java-抽象工厂模式+工厂方法模式+策略模式简单应用实战(登录场景)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java-抽象工厂模式+工厂方法模式+策略模式简单应用实战(登录场景)

前言
  • 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
  • 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
  • 策略模式是oop中最著名的设计模式之一,是对方法行为的抽象,可以归类为行为设计模式,也是oop中interface经典的应用。其特点简单又实用,是我最喜欢的模式之一。策略模式定义了一个拥有共同行为的算法族,每个算法都被封装起来,可以互相替换,独立于客户端而变化。策略模式本身的实现比较简单,但是结合单例模式+简单工厂模式+注解+反射,可以构造出近乎完善的策略模式,彻底的消除if-else。
  • 工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现

        大家假设这样一个场景,比如很多类型分别处理不同的业务逻辑,这些类型以后可能会持续增加到很多很多,最简单的办法就是是一直使用if else,这样会是我们的代码维护变得越来发咋,但根据“开-闭原则”的宗旨:对扩展开放,对修改关闭。后面就想到使用工厂模式+策略模式替代ifelse;

业务场景:

我们常见的登录业务,是每个系统都必不可少的
    登录:可以分为如下几种登录方式:
        1、 账号密码登录
        2、 手机号验证码登录
        3、 手机号一键登录
        4、 微信登录

这时候我们按照常规的开发不周的话就会使用到很多的if else 如下:

    @ApiOperation(value = "登录", notes = "用户登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名(手机号)", required = true, paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query"),
            @ApiImplicitParam(name = "loginType", value = "登录方式", defaultValue = "password:密码  code:验证码 onekey:手机号一键登陆", required = true, paramType = "query")
    })
    @PostMapping("/login")
    public Result login(@RequestParam(value = "username") String username,
                        @RequestParam(value = "password")  String password,
                        @RequestParam(value = "loginType")  int loginType) {
        if(loginType == 1){
            System.out.println("账号密码方式登录!!!");
        }else if(loginType == 2){
            System.out.println("手机号验证码方式登录!!!");
        }if(loginType == 3){
            System.out.println("手机号一键登录!!!");
        }else {
            System.out.println("登录方式错误!!!");
        }
        return Result.ok();
//        return loginService.login(dto.getLoginType(), dto.getUsername(), dto.getPassword(), null);
    }

当使用抽象工厂模式+工厂方法模式+策略模式 这些设计模式结合使用的话,就会使我们的代码变得非常简洁,维护起来也非常简单,下面直接上改进实现步骤

具体结构: 

 1、登录类型自动义注解类

import java.lang.annotation.*;


@documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface LoginChannel {

    
    String code();
}

2、登录类型code常量类

public final class LoginChannelCode {

    private LoginChannelCode() {
        throw new AssertionError("不能产生实例");
    }

    
    public static final String PASSWORD_LOGIN_CODE = "password";

    
    public static final String VERIFCODE_LOGIN_CODE = "code";

    
    public static final String ONEKEY_LOGIN_CODE = "onekey";


}

3、LoginService 登录接口入口类

import com.whcloud.wmp.utils.Result;


public interface LoginService {

    
    Result login(String loginType, String userName, String password, String code);

}
响应结果类:

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.Maps;
import com.whcloud.wmp.domain.Enum.ErrorCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.Map;


@ApiModel(value = "响应结果")
@Data
public class Result implements Serializable {
    private static final long serialVersionUID = -6190689122701100762L;

    
    @ApiModelProperty(value = "响应编码:0-请求处理成功")
    private Integer code = 0;
    
    @ApiModelProperty(value = "提示消息")
    private String message;

    
    @ApiModelProperty(value = "请求路径")
    private String path;

    
    @ApiModelProperty(value = "响应数据")
    private T data;

    
    private Integer httpStatus;

    
    @ApiModelProperty(value = "附加数据")
    private Map extra;

    
    @ApiModelProperty(value = "响应时间")
    private Long timestamp = System.currentTimeMillis();

    @JSonField(serialize = false, deserialize = false)
    @JsonIgnore
    public Integer getHttpStatus() {
        return httpStatus;
    }

    @JSonField(serialize = false, deserialize = false)
    @JsonIgnore
    public boolean isOk() {
        return this.code == ErrorCode.OK.getCode();
    }

    public static Result ok() {
        return new Result().code(ErrorCode.OK.getCode());
    }

    public static Result failed() {
        return new Result().code(ErrorCode.FAIL.getCode());
    }

    public Result code(Integer code) {
        this.code = code;
        return this;
    }

    public Result msg(String message) {
    	if (message == null) {
    		message = "";
    	}
//        this.message = i18n(message,message);
        this.message = message;
        return this;
    }

    public Result data(T data) {
        this.data = data;
        return this;
    }

    public Result path(String path) {
        this.path = path;
        return this;
    }

    public Result httpStatus(int httpStatus) {
        this.httpStatus = httpStatus;
        return this;
    }

    public Result put(String key, Object value) {
        if (this.extra == null) {
            this.extra = Maps.newHashMap();
        }
        this.extra.put(key, value);
        return this;
    }


}

4、登录接口适配器

import com.whcloud.wmp.utils.Result;


public abstract class LoginAdapter implements LoginService {

    @Override
    public Result login(String loginType, String userName, String password, String code) {
        return new Result();
    }
}

5、登录方式 代理类

import com.whcloud.wmp.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.util.Map;


@Slf4j
public class LoginDelegate extends LoginAdapter {

    @Override
    public Result login(String loginType, String userName, String password, String code) {
        LoginService loginService = getLoginService(loginType);
        if(ObjectUtils.isEmpty(loginService)){
            return Result.failed().msg("登录方式错误!!!");
        }
        return loginService.login(loginType, userName, password, code);
    }

    private Map map;

    public LoginDelegate(Map map) {
        log.info("初始化登录方式====>{}种--{}", map.size(), map);
        this.map = map;
    }


    
    private LoginService getLoginService(String loginType) {
        if (map.containsKey(loginType)) {
            return map.get(loginType);
        }
        return null;
    }
}

6、登录方式 工厂类 

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.NonNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class LoginFactoryBean implements FactoryBean, InitializingBean {

    private LoginService loginService;

    @NonNull
    private List loginServiceList;

    public List getLoginServiceList() {
        return loginServiceList;
    }

    public void setLoginServiceList(@NonNull List loginServiceList) {
        this.loginServiceList = loginServiceList;
    }

    
    @Override
    public void afterPropertiesSet() throws Exception {
        Map map = new HashMap<>(loginServiceList.size() << 1);
        for (LoginService r : loginServiceList) {
            LoginChannel channel = r.getClass().getAnnotation(LoginChannel.class);
            if (channel == null) { continue; }
            map.put(channel.code(), r);
        }
        loginService = new LoginDelegate(map);
    }

    @Override
    public LoginService getObject() throws Exception {
        return loginService;
    }

    @Override
    public Class getObjectType() {
        return loginService.getClass();
    }
}

7、登录方式 config配置类(这个是关键)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.List;


@Configuration
public class LoginChannelConfiguration {

    @Bean
    @Primary
    public LoginFactoryBean repayFactoryBean(List list) {
        LoginFactoryBean factoryBean = new LoginFactoryBean();
        factoryBean.setLoginServiceList(list);
        return factoryBean;
    }
}

8,、具体的登录方法实现类(这里之写了三种,如有增加只需要增加一个实现类即可,注意的是的类上的自定义注解 @LoginChannel(code = LoginChannelCode.VERIFCODE_LOGIN_CODE) ), 

        (1)账号密码登录实现类

import com.whcloud.wmp.channel.LoginAdapter;
import com.whcloud.wmp.channel.LoginChannel;
import com.whcloud.wmp.channel.LoginChannelCode;
import com.whcloud.wmp.utils.Result;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
@LoginChannel(code = LoginChannelCode.PASSWORD_LOGIN_CODE)
public class PasswordLogin extends LoginAdapter {


    @Override
    public Result login(String loginType, String userName, String password, String code) {
        //用户名登录方式一些参数验证逻辑
        if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) ){
            return Result.failed().msg("用户名密码不能为空!!!");
        }
        if(!"admin".equals(userName) || !"111111".equals(password) ){
            return Result.failed().msg("用户名或密码错误!!!");
        }
        return Result.ok().msg("密码方式登陆成功!!!");
    }
}

        (2)手机号验证码登录实现类

import com.whcloud.wmp.channel.LoginAdapter;
import com.whcloud.wmp.channel.LoginChannel;
import com.whcloud.wmp.channel.LoginChannelCode;
import com.whcloud.wmp.utils.Result;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;


@Component
@LoginChannel(code = LoginChannelCode.VERIFCODE_LOGIN_CODE)
public class VerifCodeLogin extends LoginAdapter {
    @Override
    public Result login(String loginType, String userName, String password, String code) {
        //验证码登录方式一些参数验证逻辑
        if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(code) ){
            return Result.failed().msg("手机号或验证码不能为空!!!");
        }
        return Result.ok().msg("验证码方式登陆成功!!!");
    }
}

        (3)手机号一键登录实现类

import com.whcloud.wmp.channel.LoginAdapter;
import com.whcloud.wmp.channel.LoginChannel;
import com.whcloud.wmp.channel.LoginChannelCode;
import com.whcloud.wmp.utils.Result;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
@LoginChannel(code = LoginChannelCode.ONEKEY_LOGIN_CODE)
public class onkeyLogin extends LoginAdapter {


    @Override
    public Result login(String loginType, String userName, String password, String code) {
        //一键登录方式一些参数验证逻辑
        if(StringUtils.isEmpty(userName)){
            return Result.failed().msg("手机号不能为空!!!");
        }
        return Result.ok().msg("一键登录方式登陆成功!!!");
    }
}

9、Controller接口入口

    @Autowired
    private LoginService loginService;
    @ApiOperation(value = "登录", notes = "用户登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名(手机号)", required = true, paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", required = true, paramType = "query"),
            @ApiImplicitParam(name = "loginType", value = "登录方式", defaultValue = "password:密码  code:验证码 onekey:手机号一键登陆", required = true, paramType = "query")
    })
    @PostMapping("/login")
    public Result login(@RequestParam(value = "username") String username,
                        @RequestParam(value = "password")  String password,
                        @RequestParam(value = "code")  String code,
                        @RequestParam(value = "loginType")  String loginType) {
//        if(loginType == 1){
//            System.out.println("账号密码方式登录!!!");
//        }else if(loginType == 2){
//            System.out.println("手机号验证码方式登录!!!");
//        }if(loginType == 3){
//            System.out.println("手机号一键登录!!!");
//        }else {
//            System.out.println("登录方式错误!!!");
//        }
//        return Result.ok();

        
        Result result = loginService.login(loginType, username, password, code);
        return result;
    }

10、实现效果

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/666641.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号