程序员的精神,不应不止于实现,更要注重优化。不应止于表面,更要研究内部机制,方能青出于蓝而胜于蓝。
1.前言
在上家公司开发后台管理系统的时候,频繁要处理各种数据显示的问题,一开始是实现就好。后来写多了,自己看得也难受了。就想着怎么优化代码和复用了。下面就通过一个简单的例子,怎么让 API 更加的实用,更好的复用。
1.代码的实用性,只能尽量,尽量再尽量。不会出现完美的API,或者是一次编写,永不修改的 API 。
2.关于实用性,API 命名和扩展性也很重要。但之前写过文章,在这里就不重复了。 [前端开发]--分享个人习惯的命名方式 , 重构 - 设计API的扩展机制
2.举个例子
比如有一个需求,有这样的数据
{
cashAmount: 236700,//回款金额(分)
cashDate: "2018-05-26 10:25:28",//回款时间
cashId: "SM2018022800020692",//回款ID
cashStatus: 0,//回款状态
createTime: "2018-05-23 10:26:25",//创建时间
custoName: "广州测试有限公司",//回款公司名称
id: "SM2018022800020692",//回款ID
merchandisers: "守候",//回款公司联系人
ordId: "SO2018022800020692",//订单ID
payChannel: null,//支付方式
remark: "",//备注
userMobile: "18819222363",//回款公司联系人电话
}
复制代码
需要对数据进行以下处理,再渲染到页面
1.cashAmount 转换成元,并保留两位小数
2.cashStatus 进行解析(0-未回款 1-已回款)
3.payChannel 进行解析 ('zfb'-支付宝,'wx'-微信支付,'cash'-现金支付,'bankTransfer'-银行转账)
4.所有值为 '' , null , undefined 的字段,全部设置为:'--'
面对这样的需要,很简单,顺手就来
let obj = {
cashAmount: 236700,//回款金额(分)
cashDate: "2018-05-26 10:25:28",//回款时间
cashId: "SM2018022800020692",//回款ID
cashStatus: 0,//回款状态
createTime: "2018-05-23 10:26:25",//创建时间
custoName: "广州测试有限公司",//回款公司名称
id: "SM2018022800020692",//回款ID
merchandisers: "守候",//回款公司联系人
ordId: "SO2018022800020692",//订单ID
payChannel: null,//支付方式
remark: "",//备注
userMobile: "13226452474",//回款公司联系人电话
}
function setValue(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
//设置金额
_obj.cashAmount = (_obj.cashAmount / 100).toFixed(2);
//解析回款状态
_obj.cashStatus = _obj.cashStatus === 0 ? '未回款' : '已回款';
//解析支付方式
let payChannelLabel = {
'zfb': '支付宝',
'wx': '微信支付',
'cash': '现金支付',
'bankTransfer': '银行转账'
}
_obj.payChannel=payChannelLabel[_obj.payChannel];
//设置默认值
for (let key in _obj){
if(_obj[key]===''||_obj[key]===null||_obj[key]===undefined){
_obj[key]='--'
}
}
return _obj;
}
obj=setValue(obj);
console.log(obj)
复制代码
结果也正确,如下图
但是如果以后需求变了,比如 userMobile 要改成 xxx xxx xxxx 这种展示方式呢?
也很简单,修改下
function setValue(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
//设置金额
//解析回款状态
//解析支付方式
/*和上面代码一样,不重复粘贴*/
//设置电话号码格式
let _formatType="xxx xxx xxxx",i = 0;
_obj.userMobile= _formatType.replace(/x/g, function(){
return _obj.userMobile[i++]
});
//设置默认值
/*和上面代码一样,不重复粘贴*/
}
复制代码
代码写好了,想必大家也开始难受了。因为每改一次需求,就要改一次 setValue 。改的多了,出现问题的概率就大了。而且,这样没复用性。试想,如果别的页面有一个需求,同样的数据。但是 cashDate 字段只需要精确到时分秒。这样的需求,大同小异。但上面的代码不适用,需要拷贝一个 setValue 方法(就叫 setValue2 吧),然后添加 cashDate 只显示 时分秒的逻辑。代码很好写
function setValue2(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
//设置金额
//解析回款状态
//解析支付方式
//设置电话号码格式
/*和上面代码一样,不重复粘贴*/
//设置 cashDate 只显示时分秒
_obj.cashDate= _obj.cashDate.split(' ')[0];
//设置默认值
/*和上面代码一样,不重复粘贴*/
}
复制代码
3.单一职责原则
想必大家更难受了,因为没发复用,导致出现了几乎完全一样的函数。这个问题解决方式很多,先说下第一个,也是一个 API 设计原则--单一职责原则。
顾名思义,单一职责原则就是让每一个函数只做一件事。下面把代码改造下
/**
* @description 设置默认值
* @param obj 待处理对象
* @return obj 已处理对象
*/
function setDefault(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
for (let key in _obj){
if(_obj[key]===''||_obj[key]===null||_obj[key]===undefined){
_obj[key]='--'
}
}
return _obj;
}
/**
* @description 格式化电话号码
* @param obj 待处理对象
* @return obj 已处理对象
*/
function setFormatMobile(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
let _formatType="xxx xxx xxxx",i = 0;
_obj.userMobile= _formatType.replace(/x/g, function(){
return _obj.userMobile[i++]
});
return _obj;
}
/**
* @description 解析支付方式
* @param obj 待处理对象
* @return obj 已处理对象
*/
function setPayChannelLabel(obj) {
let _obj=JSON.parse(JSON.stringify(obj));
let payChannelLabel = {
'zfb': '支付宝',
'wx': '微信支付',
'cash': '现金支付',
'bankTransfer': '银行转账'
}
_obj.payChannel = payChannelLabel[_obj.payChannel];
return