下面让我们一起来看一个例子 。Node有一个名为“build-url”的npm模块,用途如其名所示:构建URL 。你可以通过这个链接(https://github.com/steverydz/build-url/blob/master/src/build-url.js)查看源文件 。以下是相关代码 。
function buildUrl(url, options) {
var queryString = ;
var key;
var builtUrl;
if (url === ) {
builtUrl = '';
} else if (typeof(url) === 'object') {
builtUrl = '';
options = url;
} else {
builtUrl = url;
}
if (options) {
if (options.path) {
builtUrl += '/' + options.path;
}
if (options.queryParams) {
for (key in options.queryParams) {
if (options.queryParams.hasOwnProperty(key)) {
queryString.push(key + '=' + options.queryParams[key]);
}
}
builtUrl += '?' + queryString.join('&');
}
if (options.hash) {
builtUrl += '#' + options.hash;
}
}
return builtUrl;
};
请注意,此函数长35行 。虽然理解起来也不是非常难,但如果我们应用“小”原则来重构辅助函数,则会大大简化 。更新和改进后的版本如下 。
function buildUrl(url, options) {
const baseUrl = _getBaseUrl(url);
const opts = _getOptions(url, options);
if (!opts) {
return baseUrl;
}
urlWithPath = _AppendPath(baseUrl, opts.path);
urlWithPathAndQueryParams = _appendQueryParams(urlWithPath, opts.queryParams)
urlWithPathQueryParamsAndHash = _appendHash(urlWithPathAndQueryParams, opts.hash);
return urlWithPathQueryParamsAndHash;
};
function _getBaseUrl(url) {
if (url ===|| typeof(url) === 'object') {
return '';
}
return url;
}
function _getOptions(url, options) {
if (typeof(url) === 'object') {
return url;
}
return options;
}
function _appendPath(baseUrl, path) {
if (!path) {
return baseUrl;
}
return baseUrl += '/' + path;
}
function _appendQueryParams(urlWithPath, queryParams) {
if (!queryParams) {
return urlWithPath
}
const keyValueStrings = Object.keys(queryParams).map(key => {
return `${key}=${queryParams[key]}`;
});
const joinedKeyValueStrings = keyValueStrings.join('&');
return `${urlWithPath}?${joinedKeyValueStrings}`;
}
function _appendHash(urlWithPathAndQueryParams, hash) {
if (!hash) {
return urlWithPathAndQueryParams;
}
return `${urlWithPathAndQueryParams}#${hash}`;
}
你会注意到,虽然我们没有严格遵守每个函数4行的原则,但我们创建了几个相对“较小”的函数 。每个函数仅完成一项任务,你可以根据函数名轻松理解这段代码 。如果需要,你甚至可以针对每个函数进行单元测试,而不是只测试一个大型的buildUrl函数 。你可能还会注意到,这种方法产生的代码略多一些,从35行变成了55行 。这完全可以接受,因为这55行代码比原来的35行更加方便维护和阅读 。
如何才能编写出这样的代码?我个人认为,最简单的方法是列出你希望逐步完成的各项任务 。每一步都可以是建立某个子函数或辅助函数 。例如,针对上述buildUrl函数我们希望完成如下工作:
- 初始化baseUrl和options
- 添加路径(如果有的话)
- 添加查询参数(如果有的话)
- 添加锚点(如果有的话)
下面再来谈谈单一功能原则 。根据维基百科,单一功能原则的定义如下:
在面向对象编程领域中,单一功能原则(Single Responsibility Principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来 。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖) 。
在《代码整洁之道》中,Robert Martin给出了另一个定义:
推荐阅读
- 帮别人注册淘宝店安全吗 淘宝给别人开店有风险么
- 灌木茶和乔木茶的区别,茶树的形状乔木型
- 福鼎白茶鉴别,福鼎白茶的保留方式
- 高山茶好在哪,高山茶与平地茶鉴别法
- 田七的真假鉴别方法
- 西洋参的真假鉴别方法
- 茯砖茶和黑茶的区别,喝茯砖茶有什么效果
- 真假“千岛湖”牌茶叶,如何识别?
- 福建白茶区土壤详解,安吉白茶和福建白茶有什么区别
- 顾渚紫笋茶的冲泡方式,顾渚紫笋的鉴别方法