1. 程式人生 > >特定場景下取代if-else和switch的方式

特定場景下取代if-else和switch的方式

look-up表代替if-else

比如某平臺的信用分數評級:

超過700-950,信用極好,
650-700信用優秀,
600-650信用良好,
550-600信用中等,
350-550信用較差。

常規寫法:

function showGrace(grace) {
    let _level='';
    if(grace>=700){
        _level='信用極好'
    }
    else if(grace>=650){
        _level='信用優秀'
    }
    else if(grace>=600){
        _level='信用良好'
}
else if(grace>=550){ _level='信用中等' } else{ _level='信用較差' } return _level; }

這裡寫圖片描述

看看執行也沒問題,但是問題也是有的比如:

1- 萬一以後需求,改了比如650-750是信用優秀,750-950是信用極好。這樣就整個方法要改。

2- 方法存在各種神仙數字:700,650,600,550。日後的維護可能存在問題。

3- if-else太多,看著有點強迫症

用look-up表,把配資料置和業務邏輯分離的方式實現下

function showGrace
(grace) {
let graceForLevel=[700,650,600,550]; let levelText=['信用極好','信用優秀','信用良好','信用中等','信用較差']; for(let i=0;i<graceForLevel.length;i++){ if(grace>=graceForLevel[i]){ return levelText[i]; } } //如果不存在,那麼就是分數很低,返回最後一個 return levelText[levelText.length-1
]; }

這樣的修改,優點就是如果有需求修改,只需要修改graceForLevel,levelText。業務邏輯不需要改。

為什麼這裡推薦配資料置和業務邏輯分離

1.修改配置資料比業務邏輯修改成本更小,風險更低
2.配置資料來源和修改都可以很靈活
3.薦配置和業務邏輯分離,可以更快的找到需要修改的程式碼

如果還想靈活一些,可以封裝一個稍微通用一點的look-up函式。

通用一點的look-up函式

function showGrace(grace,level,levelForGrace) {
    for(let i=0;i<level.length;i++){
        if(grace>=level[i]){
            return levelForGrace[i];
        }
    }
    //如果不存在,那麼就是分數很低,返回最後一個
    return levelForGrace[levelForGrace.length-1];
}
let graceForLevel=[700,650,600,550];
let levelText=['信用極好','信用優秀','信用良好','信用中等','信用較差'];

第二個例項:

比如輸入一個景點,給出景點所在的城市。

最low的辦法:
function getCityForScenic(scenic) {
    let _city=''
    if(scenic==='廣州塔'){
        _city='廣州'
    }
    else if(scenic==='西湖'){
        _city='杭州'
    }
    return _city;
}
次low的辦法:
function getCityForScenic(scenic) {
    let _city='';
    let scenicOfHangZhou=['西湖','湘湖','砂之船生活廣場','京杭大運河','南宋御街'];
    if(scenic==='廣州塔'||scenic==='花城廣場'||scenic==='白雲山'){
        _city='廣州'
    }
    else if(~scenicOfHangZhou.indexOf(scenic)){
        _city='杭州'
    }
    return _city;
}
次次low的辦法: (採用 switch case)
function getCityForScenic(scenic) {
    let _city='';
    let scenicOfHangZhou=['西湖','湘湖','砂之船生活廣場','京杭大運河','南宋御街'];
    switch(true){
        case (scenic==='廣州塔'||scenic==='花城廣場'||scenic==='白雲山'):_city='廣州';break;
        case (!!~scenicOfHangZhou.indexOf(scenic)):return '杭州';   
    }
    return  _city;
}

雖然上面的程式碼出現的概率很小,但畢竟會出現。這樣的程式碼可能會造成日後維看得眼花繚亂。如果使用了配置資料和業務邏輯分離,那就可以避免這個問題。

配置資料和業務邏輯分離

function getCityForScenic(scenic) {
    let cityConfig={
        '廣州塔':'廣州',
        '花城廣場':'廣州',
        '白雲山':'廣州',
        '西湖':'杭州',
        '湘湖':'杭州',
        '京杭大運河':'杭州',
        '砂之船生活廣場':'杭州',
        '南宋御街':'杭州',
    }

    return cityConfig[scenic];
}

不習慣物件的 key 名是中文。也可以靈活處理

function getCityForScenic(scenic) {
    let cityConfig=[
        {
            scenic:'廣州塔',
            city:'廣州'
        },
        {
            scenic:'花城廣場',
            city:'廣州'
        },
        {
            scenic:'白雲山',
            city:'廣州'
        },
        {
            scenic:'西湖',
            city:'杭州'
        },
        {
            scenic:'湘湖',
            city:'杭州'
        },
        {
            scenic:'京杭大運河',
            city:'杭州'
        },
        {
            scenic:'砂之船生活廣場',
            city:'杭州'
        }
    ]
    for(let i=0;i<cityConfig.length;i++){
        if(cityConfig[i].scenic===scenic){
            return cityConfig[i].city
        }
    }
}

這裡簡單總結下,使用配置資料和業務邏輯分離的形式,好處

1- 修改配置資料比業務邏輯修改成本更小,風險更低
2- 配置資料來源和修改都可以很靈活
3- 配置和業務邏輯分離,可以更快的找到需要修改的程式碼
4- 配置資料和業務邏輯可以讓程式碼風格統一

但是並不是所有的if-else都建議這樣改造,有些需求不建議使用look-up改造。比如if-else不是很多,if判斷的邏輯不統一的使用,還是建議使用if-else方式實現。但是神仙數字,要清除。

配置物件代替switch

比如有一個需求:傳入cash,check,draft,zfb,wx_pay,對應輸出:現金,支票,匯票,支付寶,微信支付。

需求也很簡單,就一個switch就搞定了

function getPayChanne(tag){
    switch(tag){
        case 'cash':return '現金';
        case 'check':return '支票';
        case 'draft':return '匯票';
        case 'zfb':return '支付寶';
        case 'wx_pay':return '微信支付';
    }
}

但是這個的硬傷還是和上面一樣,萬一下次又要多加一個如:bank_trans對應輸出銀行轉賬呢,程式碼又要改。類似的問題,同樣的解決方案,配置資料和業務邏輯分離。程式碼如下。

function getPayChanne(tag){
    let payChanneForChinese = {
        'cash': '現金',
        'check': '支票',
        'draft': '匯票',
        'zfb': '支付寶',
        'wx_pay': '微信支付',
    };
    return payChanneForChinese[tag];
}

同理,如果想封裝一個通用的,也可以的

let payChanneForChinese = {
    'cash': '現金',
    'check': '支票',
    'draft': '匯票',
    'zfb': '支付寶',
    'wx_pay': '微信支付',
};
function getPayChanne(tag,chineseConfig){
    return chineseConfig[tag];
}
getPayChanne('cash',payChanneForChinese);

總結:

在特定場合下,代替if-else和switch的解決方案就是這麼多了。if-else,switch本身沒錯,主要是想著怎麼優化程式碼,讓程式碼更加具有可讀性,擴充套件性。