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

資訊專欄INFORMATION COLUMN

深入理解JavaScript系列8:S.O.L.I.D五大原則之里氏替換原則

susheng / 2916人閱讀

摘要:前言本章我們要講解的是五大原則語言實現的第篇,里氏替換原則。因此,違反了里氏替換原則。與行為有關,而不是繼承到現在,我們討論了和繼承上下文在內的里氏替換原則,指示出的面向對象。

前言

本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實現的第3篇,里氏替換原則LSP(The Liskov Substitution Principle )
英文原文:http://freshbrewedcode.com/derekgreer/2011/12/31/solid-javascript-the-liskov-substitution-principle/

里氏替換原則的描述是:

Subtypes must be substitutable for their base types.
派生類型必須可以替換它的基類型。

在面向對象編程里,繼承提供了一個機制讓子類共享基類的代碼,這是通過在基類型里封裝通用的數據和行為來實現的,然后以基類型來聲明更詳細的子類型,為了應用里氏替換原則,繼承子類型需要在語義上等價于基類型里的期望行為。

為了來更好的理解,請參考如下代碼:

function Vehicle(my) {
    var my = my || {};
    my.speed = 0;
    my.running = false;

    this.speed = function() {
        return my.speed;
    };
    this.start = function() {
        my.running = true;
    };
    this.stop = function() {
        my.running = false;
    };
    this.accelerate = function() {
        my.speed++;
    };
    this.decelerate = function() {
        my.speed--;
    };
    this.state = function() {
        if (!my.running) {
            return "parked";//暫停
        }
        else if (my.running && my.speed) {
            return "moving";//移動中
        }
        else if (my.running) {
            return "idle";//閑置
        }
    };
}

上述代碼我們定義了一個Vehicle函數,其構造函數為vehicle對象提供了一些基本的操作,我們來想想如果當前函數當前正運行在服務客戶的產品環境上,如果現在需要添加一個新的構造函數來實現加快移動的vehicle。思考以后,我們寫出了如下代碼:

function FastVehicle(my) {
    var my = my || {};

    var that = new Vehicle(my);
    that.accelerate = function() {
        my.speed += 3;
    };
    return that;
}

在瀏覽器的控制臺我們都測試了,所有的功能都是我們的預期,沒有問題,FastVehicle的速度增快了3倍,而且繼承他的方法也是按照我們的預期工作。此后,我們開始部署這個新版本的類庫到產品環境上,可是我們卻接到了新的構造函數導致現有的代碼不能支持執行了,下面的代碼段揭示了這個問題:

var maneuver = function(vehicle) {
    write(vehicle.state());
    vehicle.start();
    write(vehicle.state());
    vehicle.accelerate();
    write(vehicle.state());
    write(vehicle.speed());
    vehicle.decelerate();
    write(vehicle.speed());
    if (vehicle.state() != "idle") {
        throw "The vehicle is still moving!";
    }
    vehicle.stop();
    write(vehicle.state());
};

根據上面的代碼,我們看到拋出的異常是“The vehicle is still moving!”(加速一次、減速一次但是仍然沒有停止),這是因為寫這段代碼的作者一直認為加速(accelerate)和減速(decelerate)的數字是一樣的。但FastVehicle的代碼和Vehicle的代碼并不是完全能夠替換掉的。因此,FastVehicle違反了里氏替換原則。

在這點上,客戶端不能老假定vehicle都是按照這樣的規則來做,里氏替換原則(LSP)的妨礙(譯者注:就是妨礙實現LSP的代碼)不是基于我們所想的繼承子類應該在行為里確保更新代碼,而是這樣的更新是否能在當前的期望中得到實現。

上述代碼這個case,解決這個不兼容的問題需要在vehicle類庫或者客戶端調用代碼上進行一點重新設計,或者兩者都要改。

減少LSP妨礙

那么,我們如何避免LSP妨礙?不幸的話:并不是一直都是可以做到的。我們這里有幾個策略我們處理這個事情。

契約(Contracts)

處理LSP過分妨礙的一個策略是使用契約,契約清單有2種形式:執行說明書(executable specifications)和錯誤處理,在執行說明書里,一個詳細類庫的契約也包括一組自動化測試,而錯誤處理是在代碼里直接處理的,例如在前置條件,后置條件,常量檢查等,可以從Bertrand Miller的大作《契約設計》中查看這個技術。雖然自動化測試和契約設計不在本篇文字的范圍內,但當我們用的時候我還是推薦如下內容:

檢查使用測試驅動開發(Test-Driven Development)來指導你代碼的設計

設計可重用類庫的時候可隨意使用契約設計技術

對于你自己要維護和實現的代碼,使用契約設計趨向于添加很多不必要的代碼,如果你要控制輸入,添加測試是非常有必要的,如果你是類庫作者,使用契約設計,你要注意不正確的使用方法以及讓你的用戶使之作為一個測試工具。

避免繼承

避免LSP妨礙的另外一個測試是:如果可能的話,盡量不用繼承,在Gamma的大作《Design Patterns – Elements of Reusable Object-Orineted Software》中,我們可以看到如下建議:

Favor object composition over class inheritance
盡量使用對象組合而不是類繼承

有些書里討論了組合比繼承好的唯一作用是靜態類型,基于類的語言(例如,在運行時可以改變行為),與JavaScript相關的一個問題是耦合,當使用繼承的時候,繼承子類型和他們的基類型耦合在一起了,就是說及類型的改變會影響到繼承子類型。組合傾向于對象更小化,更容易想靜態和動態語言語言維護。

與行為有關,而不是繼承

到現在,我們討論了和繼承上下文在內的里氏替換原則,指示出JavaScript的面向對象。不過,里氏替換原則(LSP)的本質不是真的和繼承有關,而是行為兼容性。JavaScript是一個動態語言,一個對象的契約行為不是對象的類型決定的,而是對象期望的功能決定的。里氏替換原則的初始構想是作為繼承的一個原則指南,等價于對象設計中的隱式接口。

舉例來說,讓我們來看一下Robert C. Martin的大作《敏捷軟件開發 原則、模式與實踐》中的一個矩形類型:

矩形例子

考慮我們有一個程序用到下面這樣的一個矩形對象:

var rectangle = {
    length: 0,
    width: 0
};

過后,程序有需要一個正方形,由于正方形就是一個長(length)和寬(width)都一樣的特殊矩形,所以我們覺得創建一個正方形代替矩形。我們添加了lengthwidth屬性來匹配矩形的聲明,但我們覺得使用屬性的getters/setters一般我們可以讓lengthwidth保存同步,確保聲明的是一個正方形:

var square = {};
(function() {
    var length = 0, width = 0;
    // 注意defineProperty方式是262-5版的新特性
    Object.defineProperty(square, "length", {
        get: function() { return length; },
        set: function(value) { length = width = value; }
    });
    Object.defineProperty(square, "width", {
        get: function() { return width; },
        set: function(value) { length = width = value; }
    });
})();

不幸的是,當我們使用正方形代替矩形執行代碼的時候發現了問題,其中一個計算矩形面積的方法如下:

var g = function(rectangle) {
    rectangle.length = 3;
    rectangle.width = 4;
    write(rectangle.length);
    write(rectangle.width);
    write(rectangle.length * rectangle.width);
};

該方法在調用的時候,結果是16,而不是期望的12,我們的正方形square對象違反了LSP原則,square的長度和寬度屬性暗示著并不是和矩形100%兼容,但我們并不總是這樣明確的暗示。解決這個問題,我們可以重新設計一個shape對象來實現程序,依據多邊形的概念,我們聲明rectanglesquare,relevant。不管怎么說,我們的目的是要說里氏替換原則并不只是繼承,而是任何方法(其中的行為可以另外的行為)。

總結

里氏替換原則(LSP)表達的意思不是繼承的關系,而是任何方法(只要該方法的行為能體會另外的行為就行)。

關于本文

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

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

更多優秀文章歡迎關注我的專欄

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78463.html

相關文章

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

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

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

    摘要:,開始我們的第一篇單一職責。通過解耦可以讓每個職責工更加有彈性地變化。關于本文本文轉自大叔的深入理解系列。深入理解系列文章,包括了原創,翻譯,轉載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現將其重新整理發布。 前言 Bob大叔提出并發揚了S.O.L.I.D五大原則,用來更好地進行面向對象編程,五大原則分別是: The Single Responsibility Princi...

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

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

    chenjiang3 評論0 收藏0
  • 深入理解JavaScript系列7:S.O.L.I.D五大原則開閉原則

    摘要:前言本章我們要講解的是五大原則語言實現的第篇,開閉原則。該代碼有一個限制,就是如果再增加一個類型的話,那就需要再次修改里的條件語句,這明顯違反了開閉原則。關于本文本文轉自大叔的深入理解系列。 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實現的第2篇,開閉原則OCP(The Open/Closed Principle )。 開閉原則的描述是: Softwar...

    Cheriselalala 評論0 收藏0
  • S.O.L.I.D: PHP 面向對象設計的五個基準原則

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

    JayChen 評論0 收藏0

發表評論

0條評論

susheng

|高級講師

TA的文章

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