4

th.jpeg

2019马上就要过去了。相信临近年底的你一定和我一样有好多事情需要处理,比如:写年终总结PPT、制定下个季度OKR、需求讨论、技术方案设计、开发小伙伴找你调接口、产品小伙伴找你聊可行性等等,当然还有最重要的刷火车票。

时间紧、任务重,我该怎么办?

这许多事情堆积到一起占用了大量的时间和精力,所以此时此刻留给开发的资源就更加紧张。

就是在这种情况下,我接手了一个任务。我该怎么尽可能高效的完成它?

如果我们跳过跳过设计阶段...

权衡之下我们选择了跳过详细设计直接写代码。

好一阵埋头苦干后终于完成了任务,把键盘往前一推,心满意足地靠在椅子上,不禁感慨:“无他,唯手熟尔”。但再抬头看看时间:什么!这点玩意儿居然写到了饭点儿?顿时从虚假的成就感中惊醒了。

为什么这种为了节省时间而采取的措施最终反而却浪费了时间?实际上问题的根源是因为跳过了设计阶段。

举例来说,假设需求是要把一个包含产品名称和价格JSON数据以key:value描述列表的方式展示在页面上。代码很简单:

Object.keys(data).map(key=><span>{key}:{data[key]}</span>)

是不是 so easy ?运行一下看看效果:

price:13.5

emmmm,JSON内的key都是英文的,得把它转换为对应的中文才行。这也好办,建一个Map存储key和中文的映射即可:

const keyNameMap={
...
price:"价格"
...
}

Object.keys(data).map(key=><span>{keyNameMap[key]}:{data[key]}</span>)

这次输出就没问题了:

价格:13.5

但是demo多跑几次后发现,由于哈希表的特性,导致每次渲染不同的数据,其key的位置是不固定的。这对于用户来说很不友好,继续改:

const sortedKeyList = ['price','productName',...]
const keyNameMap={
...
price:"价格"
...
}
sortedKeyList.map(key=><span>{keyNameMap[key]}:{data[key]}</span>)

这样就保证了key的位置是固定的。然而不幸的是需求发生了一点点偏移:我们认为显示的是产品价格数据(Product),但实际上这个组件还需要支持身高体重性别类型数据(Person)、车牌号行驶证号排量型号数据(Vehicle)等几个类型......

细心如你一定发现了,这段代码不仅存在复用性不够的问题,而且健壮性也不够。这一切都是因为我们急于动手而没有进行充分的设计,于是按下葫芦浮起瓢,仿佛一个试图挽救一条到处是破洞的小船的水手,一边堵着破洞、一边又要往船外舀水。

好的实现需要有好的设计

如果一开始就进行设计的话,上述示例适合使用策略模式进行封装,针对不同的数据类型分别处理,然后统一进行渲染。这样既符合单一职责原则,也符合开闭原则

  • 单一职责原则:分离关注点,在这个示例中表现为数据与渲染分离。数据的异常不会影响渲染,反之亦然;
  • 开闭原则:对扩展开放,对修改闭合。如果有新的数据类型需要渲染,我们只需要在策略组中进行扩展即可,而不必修改原有功能。

示例代码如下:

// 策略组
const strategies = { 
    Product:(data)=>{
        let formattedList=[]
        // 处理数据
        return formattedList
    },
   Vehicle:(data)=>{
        let formattedList=[]
        // 处理数据
        return formattedList
    },
}
// 渲染方法
const renderItem=(itemList)=>{
    itemList.map(item=><span>{item.name}:{item.value}</span>)
}

通过上述的简单设计,我们不但显著的提升了代码的可扩展性、可读性,而且降低了维护成本。

请多花一点时间在设计上!

我大学老师曾经说起他学计算机时写代码都是要在脑子里跑一遍感觉没啥问题后才舍得排队去上机。如今机器不是什么稀缺资源了,但是我们的时间精力仍然宝贵。所以为了能够早点下班、少挠头,请多花点时间进行设计!

qr.001.jpeg


王亮hengg
456 声望1.1k 粉丝

资深拷贝工程师