在 segmentfault 看到一篇文章,讲 API 设计美学的文章,看到一点觉得很不错,虽然也知道应该这么做,但是一个例子胜千言啊,所以将这个内容搬过来,也加深自己的理解。感谢。
这一点就是函数的可扩展性
可扩展性,就是建议遵守开放-封闭原则。对扩展开放,对修改关闭。比如jQuery的$.fn和$.fn.extend()。
说一个简单的例子-计算加薪额度
var addMoney = (function () {
//定义策略类
var strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000;
}
};
//暴露接口
return {
//根据等级和现工资,输入加薪后的工资
compute:function(lv,money){
return strategies[lv](money)
}
};
})();
//比如:等级为A,5000+2000
console.log(addMoney.compute('A',5000))//7000
//比如:等级为B,20000+1000
console.log(addMoney.compute('B',20000))//21000
代码看着没有问题,但是如果以后需求要增加C等级呢?这就不得不修改strategies。在里面增加方法。
如下
var strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000;
},
C:function(money){
return money + 500;
}
};
这样实现也简单,如果以后要增加S等级呢?又得改strategies。这里还有一个问题就是,如果增加的C等级只有在A模块需要用到,在B模块不会出现,那么在B模块引用addMoney的时候,又会把C等级的计算方式也引入进去,造成不必要的资源浪费。
建议的方式是,设置一个接口,扩展strategies。
var addMoney = (function () {
//定义策略类
let strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000;
}
};
//暴露接口
return {
//根据等级和现工资,输入加薪后的工资
compute:function(lv,money){
return strategies[lv](money)
},
//扩展等级
addRule:function(lv,fn){
strategies[lv]=fn;
}
};
})();
//增加C等级的调用
addMoney.addRule('C',function(money){
return money + 500;
});
console.log(addMoney.compute('C',20000))//20500
这样的扩展并不好吧?怎么能随意在外部修改strategies呢?
这只是个示例,应该是要保护已经定义好的外部不可修改,但是又能够添加。