函数的命令和查询分裂

上一节,我们知道了什么是命令,以及什么是查询。今天我们继续前面的例子,来试着将一个功能太多的函数进行命令和查询的分离。
/**
* 查询函数(用于设置值并返回)
*
*/
function configure(values) {
var config = { docRoot: '/somewhere' };
var key;
for (key in values) {
config[key] = values[key];
}
return config;
}
/**
* 命令函数(用与验证config的docRoot)
*
*/
function validateDocRoot(config) {
var fs = require('fs');
var stat;
stat = fs.statSync(config.docRoot);
if (!stat.isDirectory()) {
throw new Error('Is not valid');
}
}
/**
* 命令函数(用于验证config的其他值)
*
*/
function validateSomethingElse(config){ ... }
好了,这样我们就将一个复杂的configure()
函数分离称为了三个简单的函数,且每个函数或者是命令函数或者是查询函数,这样我就方便对每个函数进行测试。
注意:前面我们说过命令函数属于setter和查询函数属于getter,而新抽象出来的configure()
函数即包含了对config对象的设置值,又返回了一个config对象,那么它到底是命令函数查询呢?
我的一个简单判断就是,因为这个函数有返回值,所以把它当做查询来进行测试。
测试代码
有了命令和查询的分离以后,我就可以对这些简单的命令和查询函数进行测试了.
describe('validate value1', ()=>{
it('accept the correct value',function(){
//expect something
});
it('accept the incorrect value',function(){
//expect something
});
});
这里我们的configure()有点小问题就是缺少了验证,因此需要重构一下:
/**
* 此函数接收一个散列对象,要么返回一个有效的配置对象要么抛出一个错误
*
*/
function configure(values) {
var config = { docRoot: '/somewhere' };
var key;
for (key in values) {
config[key] = values[key];
}
validateDocRoot(config);
validateSomethingElse(config);
return config;
}
顺便提一点,在上一个版本的验证函数中,我们看到如果抛出错误,函数返回的是一个undefined
而有了命令和查询分离以后,这个返回undefined的奇怪逻辑也不需要了。
以上函数算是初步进行了分离,但是存在的一个问题是,configure()
的测试需要依赖验证函数,可以尝试做一些抽象,比如:
var fields = {
docRoot: { validator: validateDocRoot, default: '/somewhere'},
somethingElse: { validator: validateSomethingElse}
}
function configure(values) {
var config = {};
for (var key in fields) {
if (typeof values[key] !== 'undefined') {
fields[key].validator(values[key]);
config[key] = values[key];
}else {
config[key] = fields[key].default;
}
}
return config;
}
这个函数有几个优点,验证函数可以方便的测试,对象赋值的时候可以进行验证,且数据都在一个中央位置。
当然这个函数也存在缺陷,至于到底存在什么问题呢?我们下一节进行分析。