3. 可拓展接口设计
在项目的开发过程中,接口可能会经历不同的需求,可能会越来越糟。比如下面的情况:
addModulePower(nModuleId, nPower);
经过一系列的需求变更,可能变成下面这样:
addModulePower(nModuleId,nPower,bSyncMsg,bSendEvent, bOnlyBoss)
这个接口经过各种需求的历练,加了三个参数。我们先不讨论这3个参数是否合理,当做是需求必须要加的。
对于addModulePower这样的接口,我们可以很明确的得出,它至少需要2个参数,nModuleId和nPower。那一个大的项目,它可能需要增加各种各样的参数,根据不同的参数在函数内部使用不同的计算方式。这时候我们应该是用Options这个东西了,Options在lua里面就是一个表,在typescript里面就是字典,我们将接口改成:
addModulePower(nModuleId, nPower, tOption)
以后所有的拓展接口都需要在tOption里面去加,保证了接口的干净。在函数的内部进行
if( tOption && tOption.bSyncMsg){
//做这个参数该干的事情
}
这边我们总结一下接口参数应该满足的特点:
1. 接口应该包含跟命名一致的参数,并且按照参数的重要程度依次进行定义
2. 接口应该具备可拓展性,在不同的需求下应该都是来去自如的进行功能的拓展。
这边提到的tOption这个东西,在很多地方都可以看到它的影子,比如说在微信小游戏的云开发里面:
图1
还有它对应的数据库的初始化:
图2
从图1图2可以看到,这里init接口的参数只有一个可选的options,并没有其他参数。带有options的接口是对拓展性非常友好的。
那么我们会产生一个问题,是不是所有的接口都应该改为只接受一个options参数。从大量的代码可以得出结论,并不是这样的。我们还是要将参数依靠经验以及逻辑划分出较为固定的和可变的部分,只有可变的部分才使用options进行拓展。在addModulePower(nModuleId, nPower, tOption) 这个接口的设计我们可以看出,nModuleId, nPower就是相对固定的部分。
这边涉及到一个方法论的问题。在美术培养审美的过程中,他们会被要求多看一些厉害的人画的作品,从而提升美感。对于程序而言,也是一样的,也要多看一些别人的设计。通过对这些设计进行抽象以及总结,来提高自己对于代码的驾驭能力。我们也可以通过对比,来找到合适的接口形式。比如下面这个接口:
CreateWindow("Main","Windows",WS_OVERLAPPEDWINDOW,200,200,500,500,NULL,NULL,hInstance,NULL);
我们发现经常在使用这个接口的时候传递了很多的NULL,这就是一种不舒服的调用形式,尤其容易错位。我们应该尽可能的使用可拓展的接口形式,使用者只需要关注自己需要的特性即可。