策略模式:和大量的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]();
}

最强王者

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

相关推荐
未来之窗软件服务15 分钟前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
baidu_2474386116 分钟前
Android ViewModel定时任务
android·开发语言·javascript
嘿起屁儿整29 分钟前
面试点(网络层面)
前端·网络
VT.馒头35 分钟前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
有位神秘人1 小时前
Android中Notification的使用详解
android·java·javascript
phltxy2 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron07072 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js
css趣多多3 小时前
地图快速上手
前端
zhengfei6113 小时前
面向攻击性安全专业人员的一体化浏览器扩展程序[特殊字符]
前端·chrome·safari
马猴烧酒.3 小时前
【面试八股|Java集合】Java集合常考面试题详解
java·开发语言·python·面试·八股