日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

里氏替換原則,替換的依據(jù)是什么?

來(lái)源: 責(zé)編: 時(shí)間:2024-07-12 17:23:14 662觀(guān)看
導(dǎo)讀前面幾篇文章,我們介紹了 SOLID原則的單一職責(zé)原則和開(kāi)閉原則,單一職責(zé)描述的模塊需要對(duì)一類(lèi)行為負(fù)責(zé),開(kāi)閉原則描述的是對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。今天我們就來(lái)聊聊SOLID的第三個(gè)原則:Liskov替換原則。什么是里式替換原則?里

前面幾篇文章,我們介紹了 SOLID原則的單一職責(zé)原則和開(kāi)閉原則,單一職責(zé)描述的模塊需要對(duì)一類(lèi)行為負(fù)責(zé),開(kāi)閉原則描述的是對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。今天我們就來(lái)聊聊SOLID的第三個(gè)原則:Liskov替換原則。uTB28資訊網(wǎng)——每日最新資訊28at.com

uTB28資訊網(wǎng)——每日最新資訊28at.com

什么是里式替換原則?

里式替換原則,Liskov substitution principle(簡(jiǎn)稱(chēng)LSP),它是以作者 Barbara Liskov(一位美國(guó)女性計(jì)算機(jī)科學(xué)家,對(duì)編程語(yǔ)言和分布式計(jì)算做出了開(kāi)創(chuàng)性的貢獻(xiàn),于2008年獲得圖靈獎(jiǎng))的名字命名的,Barbara Liskov 曾在1987年的會(huì)議主題演講“數(shù)據(jù)抽象”中描述了子類(lèi)型:uTB28資訊網(wǎng)——每日最新資訊28at.com

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

Liskov替換原則的核心:設(shè)Φ(x)是關(guān)于 T類(lèi)型對(duì)象 x的可證明性質(zhì)。那么對(duì)于 S類(lèi)型的對(duì)象 y,Φ(y)應(yīng)該為真,其中 S是 T的子類(lèi)型。uTB28資訊網(wǎng)——每日最新資訊28at.com

這種科學(xué)的定義是不是過(guò)于抽象,太燒腦了?因此,在實(shí)際軟件開(kāi)發(fā)中的 Liskov替換原則可以這樣:uTB28資訊網(wǎng)——每日最新資訊28at.com

The principle defines that objects of a superclass shall be replaceable with objects of its subclasses without breaking the application.That requires the objects of your subclasses to behave in the same way as the objects of your superclass.

該原則定義了在不破壞應(yīng)用程序的前提下,超類(lèi)的對(duì)象應(yīng)該可以被其子類(lèi)的對(duì)象替換,這就要求子類(lèi)對(duì)象的行為方式與您的超類(lèi)對(duì)象相同。uTB28資訊網(wǎng)——每日最新資訊28at.com

Robert C. Martin 對(duì)SLP的描述更加直接:uTB28資訊網(wǎng)——每日最新資訊28at.com

Subtypes must be substitutable for their base types.

子類(lèi)型必須可以替代它們的基本類(lèi)型。uTB28資訊網(wǎng)——每日最新資訊28at.com

通過(guò)上面幾個(gè)描述,我們可以把 LSP通俗的表達(dá)成:子類(lèi)型必須能夠替換其父類(lèi)。uTB28資訊網(wǎng)——每日最新資訊28at.com

如何實(shí)現(xiàn)Liskov替換原則?

說(shuō)起 Liskov替換原則的實(shí)現(xiàn),就不得不先看一個(gè)著名的違反 LSP設(shè)計(jì)案例:正方形/長(zhǎng)方形問(wèn)題。盡管這個(gè) case已經(jīng)有點(diǎn)老掉牙,但是為了幫助理解,我們還是炒一次剩飯。uTB28資訊網(wǎng)——每日最新資訊28at.com

數(shù)學(xué)知識(shí)告訴我們:正方形是一種特殊的長(zhǎng)方形,因此用 java代碼分別定義 Rectangle(長(zhǎng)方形) 和 Square(正方形)兩個(gè)類(lèi),并且 Square繼承 Rectangle,代碼如下:uTB28資訊網(wǎng)——每日最新資訊28at.com

// Rectangle(長(zhǎng)方形)public class Rectangle {    private int length;    private int width;    public void setLength(double length) {        this.length = length;    }    public void setWidth(double width) {        this.width = width;    }}// Square(正方形)public class Square extends Rectangle {    // 設(shè)置邊長(zhǎng)    @Override    public void setLength(double length) {        super.setLength(length);        super.setWidth(length);    }    @Override    public void setWidth(double width) {        super.setLength(width);        super.setWidth(width);    }}

假設(shè)現(xiàn)在的需求是計(jì)算幾何圖形的面積,因此面積計(jì)算代碼會(huì)如下實(shí)現(xiàn):uTB28資訊網(wǎng)——每日最新資訊28at.com

// 計(jì)算面積public int area(){    Rectangle r = new Square();     // 設(shè)置長(zhǎng)度    r.setLength(3);    // 設(shè)置寬度    r.setWidth(4);        r.getLength * r.getWidth = 3 * 4 = 12;        // 正方形    Rectangle r = new Rectangle();    // 設(shè)置長(zhǎng)度    r.setLength(3); // Length=3, Width=3    // 設(shè)置寬度    r.setWidth(4); // Length=4, Width=4        r.getLength * r.getWidth = 4 * 4 = 16;}

在這個(gè)例子中,Square類(lèi)重寫(xiě)了 setLength和 setWidth方法,以確保正方形的長(zhǎng)度和寬度總是相等的。因此:假設(shè) length=3,width=4uTB28資訊網(wǎng)——每日最新資訊28at.com

  • 對(duì)于長(zhǎng)方形,面積 = length * width= 3 * 4 = 12,符合預(yù)期;
  • 然而,用 Square對(duì)象替換 Rectangle對(duì)象時(shí),程序的行為發(fā)生了變化,本期望矩形的面積為12(3 * 4),但實(shí)際輸出為 4*4=16,違反了里氏替換原則。

如何解決這個(gè) bad case呢?uTB28資訊網(wǎng)——每日最新資訊28at.com

可以定義一個(gè)幾何圖形的接口,設(shè)定一個(gè)計(jì)算面積的方法,然后長(zhǎng)方形、正方形都實(shí)現(xiàn)這個(gè)接口,實(shí)現(xiàn)各自的面積計(jì)算邏輯,整體思路如下:uTB28資訊網(wǎng)——每日最新資訊28at.com

// 基類(lèi)public interface Geometry{     int area();}public class Rectangle implements Geometry{    private int length;    private int width;    public int area(){       return length * width;    }}public class Square implements Geometry{    private int side;    public int area(){       return side * side;    }}

我們?cè)賮?lái)看一個(gè) LSP使用的例子:uTB28資訊網(wǎng)——每日最新資訊28at.com

假設(shè)有一個(gè)股票交易的場(chǎng)景,而且需要支持債券、股票和期權(quán)等不同證券類(lèi)型的多種交易類(lèi)型,我們就可以考慮使用 LSP來(lái)解決這個(gè)問(wèn)題。uTB28資訊網(wǎng)——每日最新資訊28at.com

首先,我們定義一個(gè)交易的基類(lèi),并且在基類(lèi)中定義買(mǎi)入和賣(mài)出兩個(gè)方法實(shí)現(xiàn),代碼如下:uTB28資訊網(wǎng)——每日最新資訊28at.com

// 定義一個(gè)交易類(lèi)public class Transaction{    // 買(mǎi)進(jìn)操作    public void buy(String stock, int quantity, float price){            }    // 賣(mài)出操作    public void sell(String stock, int quantity, float price){            }}

接著,定義一個(gè)子類(lèi):股票交易,它和基類(lèi)具有相同的買(mǎi)入和賣(mài)出行為,因此,在股票交易子類(lèi)中需要重寫(xiě)基類(lèi)的方法,代碼如下:uTB28資訊網(wǎng)——每日最新資訊28at.com

// 定義股票交易子類(lèi),定義股票特定的買(mǎi)賣(mài)動(dòng)作邏輯public class StockTransaction extends Transaction{    @Override    public void buy(String stock, int quantity, float price){           }    @Override    public void sell(String stock, int quantity, float price){           }}

同樣,定義一個(gè)子類(lèi):基金交易,它和基類(lèi)具有相同的買(mǎi)入和賣(mài)出行為,因此,在基金交易子類(lèi)中需要重寫(xiě)基類(lèi)的方法,代碼如下:uTB28資訊網(wǎng)——每日最新資訊28at.com

// 定義基金交易子類(lèi),定義基金特定的買(mǎi)賣(mài)動(dòng)作邏輯public class FundTransaction extends Transaction{    @Override    public void buy(String stock, int quantity, float price){           }    @Override    public void sell(String stock, int quantity, float price){           }}

同樣,我們還可以定義了債券交易子類(lèi),債券交易和交易基類(lèi)具有相同的行為:買(mǎi)入和賣(mài)出。所以只需要重寫(xiě)基類(lèi)的方法,實(shí)現(xiàn)子類(lèi)特定的實(shí)現(xiàn)就ok了。uTB28資訊網(wǎng)——每日最新資訊28at.com

// 定義債券交易子類(lèi),定義債券特定的買(mǎi)賣(mài)動(dòng)作邏輯public class BondTransaction extends Transaction{    @Override    public void buy(String stock, int quantity, float price){           }    @Override    public void sell(String stock, int quantity, float price){            }}

上述交易的案例,股票交易和基金交易子類(lèi)替換基類(lèi)之后,并沒(méi)有破壞基類(lèi)的買(mǎi)入賣(mài)出行為,更具體地說(shuō),替換的子類(lèi)實(shí)例仍提供 buy()和 sell(),可以以相同方式調(diào)用的功能。這個(gè)符合LSP。uTB28資訊網(wǎng)——每日最新資訊28at.com

經(jīng)過(guò)我們的抽象、分離和改造之后,Stock.updateStock()類(lèi)就穩(wěn)定下來(lái)了,再也不需要增加一個(gè)事件然后增加一個(gè)else if分支處理。這種抽象帶來(lái)的好處也是很明顯的:每次有新的庫(kù)存變更事件,只需要增加一個(gè)實(shí)現(xiàn)類(lèi),其他的邏輯都不需要更改,當(dāng)庫(kù)存事件無(wú)效時(shí)只需要把實(shí)現(xiàn)類(lèi)刪除即可。uTB28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

Liskov替換原則擴(kuò)展了OCP開(kāi)閉原則,它描述的子類(lèi)型必須能夠替換其父類(lèi)型,而不會(huì)破壞應(yīng)用程序。因此,子類(lèi)需要遵循以下規(guī)則:uTB28資訊網(wǎng)——每日最新資訊28at.com

  • 不要對(duì)輸入?yún)?shù)實(shí)施比父類(lèi)實(shí)施更嚴(yán)格的驗(yàn)證規(guī)則。
  • 至少對(duì)父類(lèi)應(yīng)用的所有輸出參數(shù)應(yīng)用相同的規(guī)則。

Liskov替換原則相對(duì)前面的單一職責(zé)和開(kāi)閉原則稍微晦澀一些,因此在開(kāi)發(fā)中容易誤用,因此我們特別要注意類(lèi)之間是否存在繼承關(guān)系。uTB28資訊網(wǎng)——每日最新資訊28at.com

LSP不僅可以用在類(lèi)關(guān)系上,也可以應(yīng)用在接口設(shè)計(jì)中。uTB28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-100718-0.html里氏替換原則,替換的依據(jù)是什么?

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 一文搞懂 @Async 注解原理

下一篇: 五分鐘學(xué)完 Python 代碼編碼規(guī)范

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 永胜县| 河池市| 枣阳市| 阆中市| 布尔津县| 互助| 高雄市| 上杭县| 康平县| 微博| 麻城市| 东乡县| 永登县| 金堂县| 黔南| 黔西| 顺平县| 南靖县| 南郑县| 精河县| 邯郸县| 崇阳县| 临安市| 新昌县| 金溪县| 天祝| 辽阳县| 宁国市| 西峡县| 洪洞县| 山西省| 八宿县| 个旧市| 光山县| 夏河县| 慈利县| 怀仁县| 临邑县| 离岛区| 遵化市| 青田县|