`

代码之 DRY

 
阅读更多

直到得知 D-R-Y 这个词并不仅仅是干燥的意思,终于找到一个比模块化更好的形容词。对于你或者团队,DRY 是几乎是你代码看起来达到效果的一切。为什么?看一下这段 JS 代码,对于不同领域的人回答将会相差很多:

 

// 代码返回函数 prototype_vs_literal 所传入的参数
function prototype_vs_literal() {
    return Array.prototype.slice.call(arguments);
    // 或者
    return [].slice.call(arguments);
}

对于熟悉 JS 的同学来说,可能会考虑究竟是直接引用 prototype 快呢,还是使用字面显快。事实上他们相差无几;对于喜欢简洁的同学或者网速优化的同学来说,可能更喜欢字面量,因为节省了特别多的字符;对于喜欢代码看起来就像读语句的同学,可能更喜欢 prototype 的写法具语义。说到最后,无论是从代码本身的性能,还是其对网站所产生的网速影响来说,都是微乎其微的。这相当于说,无可挑惕,只有内行人或者我们自己才会去深入。

但,让我们来看看这样的代码:

if(condition_a) {
    var str = condition_a.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} elseif(condition_b) {
    var str = condition_b.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} elseif(condition_c) {
    var str = condition_a.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} else {
    var condition = defaultValue;
        str = condition.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
}

你可以同样改成 switch,改成任何一种写法,很多情况下,分支还是必要的。但如果分支内的还是重复着自己已经写过的代码,那么再怎么写,无论是谁,看到都会觉得或许还值得优化,让我们尝试一下修改?

修改之前说一下:DRY,是 Dont Repeat Yourself 的缩写。WikiPedia 的一个解释

In software engineering, Don’t Repeat Yourself (DRY) is a principle of software development aimed at reducing repetition of information of all kinds, especially useful in multi-tier architectures. … When the DRY principle is applied successfully, a modification of any single element of a system does not require a change in other logically unrelated elements.

那么,看看这段代码是否更 DRY 一点?

function dry(condition) {
    condition = condition || defaultValue;
    condition.trim();
    return condition.replace(/^{(\w+)}$/, function(match){
        // …
    });
}

if(condition_a) {
    dry(condition_a);
} elseif(condition_b) {
    dry(condition_b);
} elseif(condition_c) {
    dry(condition_c);
} else {
    dry();
}

把重复的逻辑抽象成一个函数,在分支中只调用函数,而不再一次定义一个新的函数内部逻辑。当然,通常情况,我们还是会认为这是不够的。为什么要重复这么多分支?那么是还可以根据情况来优化一下?当然!而原则是 DRY。

细心一点,其实关于从大方面(多行/多模块/多系统)上来说,DRY 几乎是一切。看看我们的代码,想象一下 OOP 思想,是不是也都是为了 DRY?那么,单从这点上:

一、继承

扩展父模块,获得其所拥有的方法和属性,而不用再写一次:

class Module {
    public function hello(){}
    public function dry(){…}
    …
}
class Special_Module extends Module {
    // 默认已经拥有 Module 的属性和方法
    // 比如 hello() 方法
    public function dry(){
        // 我们已经拥有 dry,有必要时我们还可以重写
    }
    public function specific_something_special(){}
}

二、封装

就拿我们上面提到过的函数来说,提供抽象的接口,并隐藏它们的具体实现。最终使用只需要调用,而不是直接再重写一遍:

function dry(condition) {
    condition = condition || defaultValue;
    condition.trim();
    return condition.replace(/^{(\w+)}$/, function(match){
        // …
    });
}

dry(‘传入的条件’);

想像一下 php 中的 is_array(),jQuery 插件,NodeJS 的 npm 包,他们都在做这样的事,提供接口,隐藏具体实现,最终提供你一个可以重用的方法、文件或者模块。像 jQuery 插件,你可以直接在页面上使用,而不用每次都复制进去一段代码:

<script src="fish.plugin.js"></script>
<script>
$('#sofish').fish()
</script>

哈哈,那么你的代码够 DRY 么?写了这么些字,也只是想说一句:Dont repeat yourself,you’re a hacker!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics