国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入理解JavaScript系列7:S.O.L.I.D五大原則之開閉原則

Cheriselalala / 839人閱讀

摘要:前言本章我們要講解的是五大原則語言實(shí)現(xiàn)的第篇,開閉原則。該代碼有一個限制,就是如果再增加一個類型的話,那就需要再次修改里的條件語句,這明顯違反了開閉原則。關(guān)于本文本文轉(zhuǎn)自大叔的深入理解系列。

前言

本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實(shí)現(xiàn)的第2篇,開閉原則OCP(The Open/Closed Principle )。

開閉原則的描述是:

Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
軟件實(shí)體(類,模塊,方法等等)應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉,即軟件實(shí)體應(yīng)當(dāng)在不修改的前提下擴(kuò)展。

open for extension(對擴(kuò)展開放)的意思是說當(dāng)新需求出現(xiàn)的時候,可以通過擴(kuò)展現(xiàn)有模型達(dá)到目的。而Close for modification(對修改關(guān)閉)的意思是說不允許對該實(shí)體做任何修改,說白了,就是這些需要執(zhí)行多樣行為的實(shí)體應(yīng)該設(shè)計成不需要修改就可以實(shí)現(xiàn)各種的變化,堅持開閉原則有利于用最少的代碼進(jìn)行項目維護(hù)。

英文原文:http://freshbrewedcode.com/derekgreer/2011/12/19/solid-javascript-the-openclosed-principle/

問題代碼

為了直觀地描述,我們來舉個例子演示一下,下屬代碼是動態(tài)展示question列表的代碼(沒有使用開閉原則)。

// 問題類型
var AnswerType = {
    Choice: 0,
    Input: 1
};

// 問題實(shí)體
function question(label, answerType, choices) {
    return {
        label: label,
        answerType: answerType,
        choices: choices // 這里的choices是可選參數(shù)
    };
}

var view = (function () {
    // render一個問題
    function renderQuestion(target, question) {
        var questionWrapper = document.createElement("div");
        questionWrapper.className = "question";

        var questionLabel = document.createElement("div");
        questionLabel.className = "question-label";
        var label = document.createTextNode(question.label);
        questionLabel.appendChild(label);

        var answer = document.createElement("div");
        answer.className = "question-input";

        // 根據(jù)不同的類型展示不同的代碼:分別是下拉菜單和輸入框兩種
        if (question.answerType === AnswerType.Choice) {
            var input = document.createElement("select");
            var len = question.choices.length;
            for (var i = 0; i < len; i++) {
                var option = document.createElement("option");
                option.text = question.choices[i];
                option.value = question.choices[i];
                input.appendChild(option);
            }
        }
        else if (question.answerType === AnswerType.Input) {
            var input = document.createElement("input");
            input.type = "text";
        }

        answer.appendChild(input);
        questionWrapper.appendChild(questionLabel);
        questionWrapper.appendChild(answer);
        target.appendChild(questionWrapper);
    }

    return {
        // 遍歷所有的問題列表進(jìn)行展示
        render: function (target, questions) {
            for (var i = 0; i < questions.length; i++) {
                renderQuestion(target, questions[i]);
            };
        }
    };
})();

var questions = [
                question("Have you used tobacco products within the last 30 days?", AnswerType.Choice, ["Yes", "No"]),
                question("What medications are you currently using?", AnswerType.Input)
                ];

var questionRegion = document.getElementById("questions");
view.render(questionRegion, questions);

上面的代碼,view對象里包含一個render方法用來展示question列表,展示的時候根據(jù)不同的question類型使用不同的展示方式,一個question包含一個label和一個問題類型以及choices的選項(如果是選擇類型的話)。如果問題類型是Choice那就根據(jù)選項生產(chǎn)一個下拉菜單,如果類型是input,那就簡單地展示input輸入框。

該代碼有一個限制,就是如果再增加一個question類型的話,那就需要再次修改renderQuestion里的條件語句,這明顯違反了開閉原則。

重構(gòu)代碼

讓我們來重構(gòu)一下這個代碼,以便在出現(xiàn)新question類型的情況下允許擴(kuò)展view對象的render能力,而不需要修改view對象內(nèi)部的代碼。

先來創(chuàng)建一個通用的questionCreator函數(shù):

function questionCreator(spec, my) {
    var that = {};

    my = my || {};
    my.label = spec.label;

    my.renderInput = function () {
        throw "not implemented";
        // 這里renderInput沒有實(shí)現(xiàn),主要目的是讓各自問題類型的實(shí)現(xiàn)代碼去覆蓋整個方法
    };

    that.render = function (target) {
        var questionWrapper = document.createElement("div");
        questionWrapper.className = "question";

        var questionLabel = document.createElement("div");
        questionLabel.className = "question-label";
        var label = document.createTextNode(spec.label);
        questionLabel.appendChild(label);

        var answer = my.renderInput();
        // 該render方法是同樣的粗合理代碼
        // 唯一的不同就是上面的一句my.renderInput()
        // 因?yàn)椴煌膯栴}類型有不同的實(shí)現(xiàn)

        questionWrapper.appendChild(questionLabel);
        questionWrapper.appendChild(answer);
        return questionWrapper;
    };

    return that;
}

該代碼的作用組合要是render一個問題,同時提供一個未實(shí)現(xiàn)的renderInput方法以便其他function可以覆蓋,以使用不同的問題類型,我們繼續(xù)看一下每個問題類型的實(shí)現(xiàn)代碼:

function choiceQuestionCreator(spec) {

    var my = {},
    that = questionCreator(spec, my);
    // choice類型的renderInput實(shí)現(xiàn)
    my.renderInput = function () {
        var input = document.createElement("select");
        var len = spec.choices.length;
        for (var i = 0; i < len; i++) {
            var option = document.createElement("option");
            option.text = spec.choices[i];
            option.value = spec.choices[i];
            input.appendChild(option);
        }

        return input;
    };

    return that;
}

function inputQuestionCreator(spec) {

    var my = {},
    that = questionCreator(spec, my);

    // input類型的renderInput實(shí)現(xiàn)
    my.renderInput = function () {
        var input = document.createElement("input");
        input.type = "text";
        return input;
    };

    return that;
}

choiceQuestionCreator函數(shù)和inputQuestionCreator函數(shù)分別對應(yīng)下拉菜單和input輸入框的renderInput實(shí)現(xiàn),通過內(nèi)部調(diào)用統(tǒng)一的questionCreator(spec, my)然后返回that對象(同一類型哦)。

view對象的代碼就很固定了。

var view = {
    render: function(target, questions) {
        for (var i = 0; i < questions.length; i++) {
            target.appendChild(questions[i].render());
        }
    }
};

所以我們聲明問題的時候只需要這樣做,就OK了:

var questions = [
    choiceQuestionCreator({
        label: "Have you used tobacco products within the last 30 days?",
        choices: ["Yes", "No"]
  }),
    inputQuestionCreator({
        label: "What medications are you currently using?"
  })
    ];

最終的使用代碼,我們可以這樣來用:

var questionRegion = document.getElementById("questions");

view.render(questionRegion, questions);
最終代碼

最終代碼

上面的代碼里應(yīng)用了一些技術(shù)點(diǎn),我們來逐一看一下:

首先,questionCreator方法的創(chuàng)建,可以讓我們使用模板方法模式將處理問題的功能delegat給針對每個問題類型的擴(kuò)展代碼renderInput上。

其次,我們用一個私有的spec屬性替換掉了前面question方法的構(gòu)造函數(shù)屬性,因?yàn)槲覀兎庋b了render行為進(jìn)行操作,不再需要把這些屬性暴露給外部代碼了。

第三,我們?yōu)槊總€問題類型創(chuàng)建一個對象進(jìn)行各自的代碼實(shí)現(xiàn),但每個實(shí)現(xiàn)里都必須包含renderInput方法以便覆蓋questionCreator方法里的renderInput代碼,這就是我們常說的策略模式。

通過重構(gòu),我們可以去除不必要的問題類型的枚舉AnswerType,而且可以讓choices作為choiceQuestionCreator函數(shù)的必選參數(shù)(之前的版本是一個可選參數(shù))。

總結(jié)

重構(gòu)以后的版本的view對象可以很清晰地進(jìn)行新的擴(kuò)展了,為不同的問題類型擴(kuò)展新的對象,然后聲明questions集合的時候再里面指定類型就行了,view對象本身不再修改任何改變,從而達(dá)到了開閉原則的要求。

另:懂C#的話,不知道看了上面的代碼后是否和多態(tài)的實(shí)現(xiàn)有些類似?其實(shí)上述的代碼用原型也是可以實(shí)現(xiàn)的,大家可以自行研究一下。

關(guān)于本文

本文轉(zhuǎn)自TOM大叔的深入理解JavaScript系列。關(guān)于S.O.L.I.D系列的五篇文章我糾結(jié)了很久,本來不想去整理的,但最終發(fā)現(xiàn)其實(shí)中間說的很多都是關(guān)于OOP(面向?qū)ο?編碼原則的東西,十分值得研讀,所以最后還是決定整理出來。

【深入理解JavaScript系列】文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,原文是TOM大叔的一個非常不錯的專題,現(xiàn)將其重新整理發(fā)布。謝謝大叔。如果你覺得本文不錯,請幫忙點(diǎn)個推薦,支持一把,感激不盡。

更多優(yōu)秀文章歡迎關(guān)注我的專欄

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78465.html

相關(guān)文章

  • 深入理解JavaScript系列9:S.O.L.I.D五大原則之接口隔離原則

    摘要:前言本章我們要講解的是五大原則語言實(shí)現(xiàn)的第篇,接口隔離原則。接口隔離原則和單一職責(zé)有點(diǎn)類似,都是用于聚集功能職責(zé)的,實(shí)際上可以被理解才具有單一職責(zé)的程序轉(zhuǎn)化到一個具有公共接口的對象。與我們下面討論的一些小節(jié)是里關(guān)于違反接口隔離原則的影響。 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實(shí)現(xiàn)的第4篇,接口隔離原則ISP(The Interface Segreg...

    piglei 評論0 收藏0
  • 深入理解JavaScript系列6:S.O.L.I.D五大原則之單一職責(zé)

    摘要:,開始我們的第一篇單一職責(zé)。通過解耦可以讓每個職責(zé)工更加有彈性地變化。關(guān)于本文本文轉(zhuǎn)自大叔的深入理解系列。深入理解系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現(xiàn)將其重新整理發(fā)布。 前言 Bob大叔提出并發(fā)揚(yáng)了S.O.L.I.D五大原則,用來更好地進(jìn)行面向?qū)ο缶幊蹋宕笤瓌t分別是: The Single Responsibility Princi...

    walterrwu 評論0 收藏0
  • 深入理解JavaScript系列8:S.O.L.I.D五大原則之里氏替換原則

    摘要:前言本章我們要講解的是五大原則語言實(shí)現(xiàn)的第篇,里氏替換原則。因此,違反了里氏替換原則。與行為有關(guān),而不是繼承到現(xiàn)在,我們討論了和繼承上下文在內(nèi)的里氏替換原則,指示出的面向?qū)ο蟆? 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實(shí)現(xiàn)的第3篇,里氏替換原則LSP(The Liskov Substitution Principle )。英文原文:http://fre...

    susheng 評論0 收藏0
  • 深入理解JavaScript系列10:S.O.L.I.D五大原則之依賴倒置原則

    摘要:前言本章我們要講解的是五大原則語言實(shí)現(xiàn)的第篇,依賴倒置原則。當(dāng)應(yīng)用依賴倒置原則的時候,關(guān)系就反過來了。在當(dāng)靜態(tài)類型語言的上下文里討論依賴倒置原則的時候,耦合的概念包括語義和物理兩種。依賴倒置原則和依賴注入都是關(guān)注依賴,并且都是用于反轉(zhuǎn)。 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實(shí)現(xiàn)的第5篇,依賴倒置原則LSP(The Dependency Invers...

    chenjiang3 評論0 收藏0
  • S.O.L.I.D: PHP 面向?qū)ο笤O(shè)計的五個基準(zhǔn)原則

    摘要:是首個個面向?qū)ο笤O(shè)計準(zhǔn)則的首字母縮寫,這些準(zhǔn)則是由提出的他更為人所熟知的名字是。單一功能原則開閉原則里氏替換原則接口隔離原則依賴反轉(zhuǎn)原則接下來讓我們看看每個原則,來了解為什么可以幫助我們成為更好的開發(fā)人員。 showImg(https://segmentfault.com/img/remote/1460000019313380?w=1680&h=656); S.O.L.I.D?是?首個...

    JayChen 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<