策略模式:和大量的if-else说拜拜~

在群里看到群友提问:

先来模拟下他的代码:

jsx 复制代码
// 模拟后端返回数据
let item = {
    targetName: '低',
    viewMod: '场景', // 或者 '区域'
    thresholdValue: '2,4,6,8',
    tatgetAlgo: ''
};

// 模拟逻辑
if (item.targetName == '无') {
    item.tatgetAlgo = '根满分';
} else if (item.targetName == '弱') {
    if (item.viewMod.indexOf('场景') > -1) {
        let arr = item.thresholdValue.split(',', 7);
        item.tatgetAlgo = `以下 ${arr[0]} % ;`;
    } else if (item.viewMod.indexOf('区域') > -1) {
        let arr = item.thresholdValue.split(',', 3);
        item.tatgetAlgo = `1、问题 ${arr[0]} ;`;
    }
} else if (item.targetName == '低') {
    if (item.viewMod.indexOf('场景') > -1) {
        let arr = item.thresholdValue.split(',', 4);
        item.tatgetAlgo = `以下 ${arr[3]}G;`;
    } else if (item.viewMod.indexOf('区域') > -1) {
        let arr = item.thresholdValue.split(',', 2);
        item.tatgetAlgo = `1、问题得分`;
    }
}

可以看到有大量的if判断操作,逻辑比较复杂,如果线上有bug,处理起来也很麻烦。那么有什么好的方式来优化分支代码呢? ps:文章末尾有方案哦

先来看一个简单的例子:

定义一个名为 speak 的函数,该函数根据传入的参数 name 的不同值输出不同的字符串。具体来说:

  • 如果 name 的值是 '剑圣',则输出 '真正的大师永远都怀着一颗学徒的心。'
  • 如果 name 的值是 '盖伦',则输出 '生命不息,战斗不止。'
  • 如果 name 的值是 '阿木木',则输出 '我还以为你从来都不会选我呢。'
  • 如果 name 的值是 '诺手',则输出 '只有我才能带领我们走向胜利。'
  • 如果 name 的值不是以上任何一个值,那么输出 '我是谁?'

青铜

jsx 复制代码
function speak(name){
    if(name==='剑圣'){
        console.log('真正的大师永远都怀着一颗学徒的心。')
    } else if(name==='盖伦'){
        console.log('生命不息,战斗不止。')
    } else if(name==='阿木木'){
        console.log('我还以为你从来都不会选我呢。')
    } else if(name==='诺手'){
        console.log('只有我才能带领我们走向胜利。')
    } else {
       console.log('我是谁?')
    }
}

speak('诺手') //'只有我才能带领我们走向胜利。'

问题:代码中含有大量的 if-else 判断逻辑,维护困难。当代码逻辑数量达到几百个时,代码的可读性大大降低。

白银

白银参考了策略模式的思路,将逻辑封装到一个对象中。这种方式使得这个对象能够独立出来,只需专注于维护这个对象本身即可。

jsx 复制代码
function speak(name){
    let map = {
        '剑圣': '真正的大师永远都怀着一颗学徒的心。',
        '盖伦': '生命不息,战斗不止。',
        '阿木木': '我还以为你从来都不会选我呢。',
        '诺手': '只有我才能带领我们走向胜利。',
    }

    if(map[name]){
       console.log(map[name])
    } else {
       console.log('我是谁?')
    }
}

speak('诺手') //'只有我才能带领我们走向胜利。'

问题:这里的方法都一致只是参数不同,,盖伦说我需要蹲草丛里,我是草丛伦,阿木木说猥琐发育等我六级,诺手说无情铁手致命打击大杀四方。这样写,似乎是没问题的。但如果每个方法不同,阁下该如何应对呢?比如在说台词之后,需要有自己单独的逻辑,比如盖伦说生命不息,战斗不止后再说我需要蹲草丛里,我是草丛伦

黄金

将对象中的处理逻辑单独封装成一个函数,内部处理自己的逻辑。

jsx 复制代码
function speak(name){
    let map = {
        '剑圣': ()=> {
            console.log('真正的大师永远都怀着一颗学徒的心。','你们先上我开团')
         },
        '盖伦': ()=> { 
            console.log('生命不息,战斗不止');
            console.log('我需要蹲草丛里,我是草丛伦')
         },
        '阿木木': ()=> {
            console.log('我还以为你从来都不会选我呢');
            console.log('猥琐发育等我六级');
            console.log('猥琐发育等我六级!!');
         },
        '诺手': ()=> {
            console.log('无情铁手致命打击大杀四方')
        },
    }

    if(map[name]){
      map[name]()
    } else {
       console.log('我是谁?')
    }
}

speak('剑圣') //'真正的大师永远都怀着一颗学徒的心。' '你们先上我开团'

问题: 现在回答逻辑抽离出来了,但是判断逻辑还是有问题,。如果每个条件中的判断逻辑不一样怎么办呢?

铂金

我要除了判断姓名外,还要判断剑圣和盖伦的武器是什么不是剑,要判断阿木木等级是不是大于等于6级。诺手的等级是不大于等于16级。铂金可能会选择返璞归真,直接用if else实现,这样的逻辑很常见,也比较清晰一些。

jsx 复制代码
function speak(name,weapon,level){
    if(name==='剑圣' && weapon.includes('剑')){
        console.log('真正的大师永远都怀着一颗学徒的心。','你们先上我开团')
    }else if(name==='盖伦'&&weapon.includes('剑')){
         console.log('生命不息,战斗不止');
         console.log('我需要蹲草丛里,我是草丛伦');
    }else if(name==='阿木木'&&level>=6){
        console.log('我还以为你从来都不会选我呢');
        console.log('猥琐发育等我六级');
        console.log('猥琐发育等我六级!!');
    }else if(name==='诺手'&&level>=16){
        console.log('无情铁手致命打击大杀四方')
    }else {
       console.log('我是谁?')
    }
}

speak('盖伦','大宝剑',4) //'生命不息,战斗不止'  //'我需要蹲草丛里,我是草丛伦'
speak('盖伦','大保健',6) //'我是谁?'

钻石

怎么将上面的逻辑封装成策略模式呢?来看看钻石的做法。首先将map改造成一个二维数组,每一子项数组中第一项是判断逻辑函数,第二项是回答逻辑函数。

jsx 复制代码
function speak(name,weapon,level){
    let map = [
        [ 
            ()=> { name==='剑圣' && weapon.includes('剑') }, 
            ()=> { console.log('真正的大师永远都怀着一颗学徒的心。','你们先上我开团')}
        ],
        [ 
            ()=> { name==='盖伦' && weapon.includes('剑') }, 
            ()=> { console.log('生命不息,战斗不止'); console.log('我需要蹲草丛里,我是草丛伦')}
        ],
        [ 
            ()=> { name==='阿木木' && level>=6}, 
            ()=> {  console.log('我还以为你从来都不会选我呢');console.log('猥琐发育等我六级'); console.log('猥琐发育等我六级!!');}
        ],
        [ 
            ()=> { name==='诺手' && level>=16 }, 
            ()=> { console.log('无情铁手致命打击大杀四方') }
        ],
    ]
    const target = map.find(item=>item[0]())
    if(target){
      target[1]()
    } else {
       console.log('我是谁?')
    }
}

speak('盖伦','大宝剑',4) //'生命不息,战斗不止'  //'我需要蹲草丛里,我是草丛伦'
speak('盖伦','大保健',6) //'我是谁?'

同理,按照这个思路可以把文章开头的例子优化了:

jsx 复制代码
// 调用示例
const item = {
    targetName: '弱',
    viewMod: ['场景'],
    thresholdValue: '1,2,3,4,5,6,7'
};

let map = [
    [
        () => item.targetName === '无',
        () => {
            item.tatgetAlgo = '根满分';
        }
    ],
    [
        () => item.targetName === '弱' && item.viewMod.indexOf('场景') > -1,
        () => {
            let arr = item.thresholdValue.split(',', 7);
            item.tatgetAlgo = `以下 ${arr[0]} % ;`;
        }
    ],
    [
        () => item.targetName === '弱' && item.viewMod.indexOf('区域') > -1,
        () => {
            let arr = item.thresholdValue.split(',', 3);
            item.tatgetAlgo = `1、问题 ${arr[0]} ;`;
        }
    ],
    [
        () => item.targetName === '低' && item.viewMod.indexOf('场景') > -1,
        () => {
            let arr = item.thresholdValue.split(',', 4);
            item.tatgetAlgo = `以下 ${arr[3]}G;`;
        }
    ],
    [
        () => item.targetName === '低' && item.viewMod.indexOf('区域') > -1,
        () => {
            let arr = item.thresholdValue.split(',', 2);
            item.tatgetAlgo = `1、问题得分`;
        }
    ]
];

const target = map.find(item => item[0]());
if (target) {
    target[1]();
}

最强王者

最强王者段位的代码,就靠评论区的各位了~

相关推荐
喵叔哟20 分钟前
重构代码之取消临时字段
java·前端·重构
还是大剑师兰特1 小时前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解1 小时前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django