表驱动法(更优雅的写if-else、switch-case)

表驱动法是一种编程模式,用于替代复杂的if-else或switch-case语句。通过将数据存储在表中,实现更简洁、易维护的代码。文章介绍了直接访问、阶梯访问等应用场景,并展示了如何在处理星期几、月份天数以及评分等级等场景下运用表驱动法,提高代码的可读性和可扩展性。同时,讨论了在阶梯访问中注意的端点处理、二分查找优化等问题。

表驱动法

表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if
和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。

直接访问

一个很简单的例子: 今天星期几

const day = new Date().getDay()
let day_zh;
if(day === 0){
    day_zh = '星期日'
}else if(day === 1) {
    day_zh = '星期一'
}
...
else{
    day_zh = '星期六'
}

// 或者 用 switch case
switch(day) {
    case 0:
        day_zh = '星期日'
        break;
    case 1:
        day_zh = '星期一'
        break;
        ...
}


实现同样功能的一种更简单、更容易修改的方法是把这些数据存到一张表里面。

const week = ['星期日', '星期一',..., '星期六']
const day = new Date().getDay(
const day_zh = week[day]

第二个例子:假设你需要一个可以返回每个月中天数的函数(为简单起见不考虑闰年)
使用if else

function iGetMonthDays(iMonth) {
  let iDays;
  if(1 == iMonth) {iDays = 31;}
  else if(2 == iMonth) {iDays = 28;}
  else if(3 == iMonth) {iDays = 31;}
  else if(4 == iMonth) {iDays = 30;}
  else if(5 == iMonth) {iDays = 31;}
  else if(6 == iMonth) {iDays = 30;}
  else if(7 == iMonth) {iDays = 31;}
  else if(8 == iMonth) {iDays = 31;}
  else if(9 == iMonth) {iDays = 30;}
  else if(10 == iMonth) {iDays = 31;}
  else if(11 == iMonth) {iDays = 30;}
  else if(12 == iMonth) {iDays = 31;}
  return iDays;
}

使用表驱动(包括闰年判断)

const monthDays = [
  [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
function getMonthDays(month, year) {
  let isLeapYear = (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0) ? 1 : 0
  return monthDays[isLeapYear][(month - 1)];
}
console.log(getMonthDays(2, 2000))

对象中的应用
形如:

if (key = "Key A")
{
   处理 Key A 相关的数据。
}
else if (key = "Key B")
{
   处理 Key B 相关的数据。
}

if (key = "Key A")
{
   执行 Key A 相关的行为。
}
else if (key = "Key B")
{
   执行 Key B 相关的行为。
}

可以改装成:

let table = {
  A: {
    data: "数据1",
    action: "行为1"
  },
  B: {
    data: "数据2",
    action: "行为2"
  }
}

function handleTable(key) {
  return table[key]
}
console.log(handleTable('A').data)

let table = {
  A: {
    data: "数据1",
    action () {
      console.log('action 1')
    }
  },
  B: {
    data: "数据2",
    action () {
      console.log('action 2')
    }
  }
}

function handleTable(key) {
  return table[key]
}
handleTable('A').action()

回顾一下我以前写的代码,好多复杂的代码都通过这种方式简化了不少,比如:

let vm = this
let adTable = {
  bdkq () {
    window.clLib.localStorageOperating.updateData('default_hospital_code', '871978')
    vm.$router.push('/hospital')
  },
  etyy () { vm.goSp(10012) },
  szn () { vm.goCh('szn') }
}
adTable[data.key] ? adTable[data.key]() : location.href = data.ad_url

以前是怎么写的呢? 看看就知道了,特别复杂!

switch (data.key) {
  case 'bdkq':
    window.clLib.localStorageOperating.updateData('default_hospital_code', '871978')
    this.$router.push('/hospital')
    break
  case 'etyy':
    this.goSp(10012)
    break
  case 'szn':
    this.goCh('szn')
    break
  default:
    location.href = data.ad_url
    break
}

阶梯访问
这种方法不像索引访问那么直接,但比索引访问要节省空间。

典型的例子就是等级评定

考试按分数评优良中差四个等级

简单做法

    let level = '优'
    if(score <60 ){
        level = '差'
    }else if(score < 80) {
        level = '中'
    }else if(score < 90) {
        level = '良'
    }

如果需要添加等级 60-70 之间 是一般,就需要改逻辑,逻辑简单的还好

    let level = '优'
    if(score <60 ){
        level = '差'
    }else if(score < 70) {
        level = '一般'
    }else if(score < 80) {
        level = '中'
    }else if(score < 90) {
        level = '良'
    }

这时用阶梯查询就比较方便,而且扩展性也好

    const levelTable = ['差', '中', '良', '优']
    const scoreCeilTable = [60, 80, 90, 100]
    
    function getLevel(score) {
        const len = scoreCeilTable.length
        for(let i = 0; i < len; i++) {
            const scoreCeil = scoreCeilTable[i]
            if(score <= scoreCeil) {
                return levelTable[i]
            }
            
        }
        return levelTable[len - 1]
    }
    

就算后面需要添加等级60-70 —> ‘一般’ 也只需要简单添加数据表就可以了,而不需要修改逻辑

    const levelTable = ['差', '一般', '中', '良', '优']
    const scoreCeilTable = [60, 70, 80, 90, 100]

阶梯访问表需要注意几个问题

  1. 留心端点
  2. 二分查找替代顺序查找:上面例子用了顺序查找,当数据比较大时,查找成本还是比较大的,应该考虑用二分查找替代顺序查找
  3. 考虑用索引访问来取代阶梯技术,阶梯查找比较耗时,如果速度非常重要,可以用索引访问来取代阶梯,用空间换时间,但也要分情况,因为离散空间是不能够完全替代连续空间的

二分查找跳转

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值