【设计模式】策略模式demo_很好理解

目录

1.背景

2.需求

3.思考

4.旧代码if-else

5.新代码-策略模式

6.总结

1.背景

        想起以前项目中有权限判断,决定用户当前能执行什么操作,一大堆if-else,多一个角色就多一个if-else,虽然领导说这个需求不会变,但谁知道呢,我们要保证扩展性和易读性。

2.需求

        一个工作流相关的问题,但前提是不使用工作流框架,领导说比较简单的审批流程而且不会再变动了,用几个表实现+标识就可以实现,意思是XX角色在XX环节应该有什么权限个操作。

3.思考

        看着一大堆if-else,再来一个角色就多一个if,易读性极差,而且逻辑太多了,很多判断嵌套,但是最终都是输出一个/系列参数或者执行一个方法。        

4.旧代码if-else

        为了更好的理解,我就在controller写出来,不在serviceImpl写了,节省大家理解时间。

        角色一共分3种,安保、老师、学生,每个角色都会说他们身份的话,对应都是speak()方法。根据入参roleCode角色编号,判断是哪个角色,应该返回他们所说的话。

        安保:我是安保人员,我可以保卫老师和学生们。

        老师:我是老师,我很好地管理我的班级。

        学生:我是学生,我已经完成我的作业了。

@RequestMapping("/home")
@RestController
public class HomeController {
    // 旧代码-if-else
    @RequestMapping("/strategyBefore")
    public String strategyBefore(Integer roleCode) {
        switch (roleCode) {
            case 1: // 安保
                return "I am a security, I can protect teachers and students";
            case 2: // 老师
                return "I am a teacher, I adjusted really well to my class.";
            case 3: // 学生
                return "I am a student, I have completed my homework";
            default:
                throw new RuntimeException("Can not find the role") ;
        }
    }
}

5.新代码-策略模式

        采用简单工厂模式+策略模式,1个枚举+1个接口+1个工厂+n个策略实现类,迫切需要解决的就是判断问题。

        Controller:新代码

@RequestMapping("/home")
@RestController
public class HomeController {
    // 新代码-策略模式
    @RequestMapping("/strategyAfter")
    public String strategyAfter(Integer roleCode) {
        IRole role = RoleFactory.getRole(roleCode);
        return role.speak();
    }
}

        枚举类:用在工厂类里,利用hashMap的key-value特性和get()方法解决了判断值问题。

/**
 * @author  chengqinhong
 * @date    2022/12/12 11:16
 * @description 角色权限枚举
 */
public enum RoleEnum {

    SECURITY(1, "security"), // 安保
    TEACHER(2, "teacher"), // 老师
    STUDENT(3, "student"); // 学生

    private final int code;
    private final String msg;

    RoleEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

        接口类:声明一个方法,各个实现类都实现该方法,但是不同的类该方法的逻辑代码不一致。

/**
 * @author chengqinhong
 * @date 2022/12/11 22:11
 * @description 策略模式定义的接口
 */
public interface IRole {
    // 角色权限查询返回接口
    String speak();
}

        工厂类:获取对象

/**
 * @author  chengqinhong
 * @date    2022/12/12 11:21
 * @description 获取角色对象工厂
 */
public class RoleFactory {
    public static Map<Integer, IRole> roleMap = new HashMap<>();

    // 利用key-value形式区分不同的角色对应的的实体类
    static {
        roleMap.put(RoleEnum.SECURITY.getCode(), new SecurityImpl());
        roleMap.put(RoleEnum.TEACHER.getCode(), new TeacherImpl());
        roleMap.put(RoleEnum.STUDENT.getCode(), new StudentImpl());
    }

    public static IRole getRole(Integer roleCode) {
        IRole role = roleMap.get(roleCode);
        if (role == null) {
            throw new RuntimeException("Can not find the role");
        }
        return role;
    }
}

        策略实现类:不同角色对该方法都有不同的逻辑

        角色- 安保

import com.example.demoWeb.service.IRole;
/**
 * @author  chengqinhong
 * @date    2022/12/11 22:13
 * @description 角色-安保
 */
public class SecurityImpl implements IRole {
    @Override
    public String speak() {
        return "I am a security, I can protect teachers and students";
    }
}

         角色-老师

import com.example.demoWeb.service.IRole;
/**
 * @author  chengqinhong
 * @date    2022/12/11 22:13
 * @description 角色-老师
 */
public class TeacherImpl implements IRole {
    @Override
    public String speak() {
        return "I am a teacher, I adjusted really well to my class.";
    }
}

         角色-学生

import com.example.demoWeb.service.IRole;
/**
 * @author  chengqinhong
 * @date    2022/12/11 22:13
 * @description 角色-学生
 */
public class StudentImpl implements IRole {
    @Override
    public String speak() {
        return "I am a student, I have completed my homework";
    }
}

        新旧代码对比 :新代码-策略模式的易读性完胜旧代码-if-else

@RequestMapping("/home")
@RestController
public class HomeController {


    // 新代码-策略模式
    @RequestMapping("/strategyAfter")
    public String strategyAfter(Integer roleCode) {
        IRole role = RoleFactory.getRole(roleCode);
        return role.speak();
    }

    // 旧代码-if-else
    @RequestMapping("/strategyBefore")
    public String strategyBefore(Integer roleCode) {
        switch (roleCode) {
            case 1: // 安保
                return "I am a security, I can protect teachers and students";
            case 2: // 老师
                return "I am a teacher, I adjusted really well to my class.";
            case 3: // 学生
                return "I am a student, I have completed my homework";
            default:
                throw new RuntimeException("Can not find the role") ;
        }
    }
}

6.总结

        从整个项目开发的角度和维护的角度来说,有很大帮助!        

        从代码的易读性来说,有很大的提高!

        从代码数来说,代码量膨胀了好几倍...

        从软件的设计难度来说,有一点点提高。

        注意其中有简单工厂模式则不可避免的是‘开-闭 原则’,不好实现扩展性,因为每次新增模式都要修改原来的简单工厂类。

        从个人的设计水平来说,是有很大的提高,这个设计模式带来的思考是很不一样的,不再是死亡if-else,自己写的头疼,后人接手也看不明白,需求有一点点逻辑变动就要改代码重新构建发布等等。该模式结合数据库维护实现可配置/接口进行维护/后台管理已有的策略,有变更的需求可以简单操就达到效果,提高了灵活性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值