成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

里氏替換原則,替換的依據是什么?

開發
Liskov替換原則相對前面的單一職責和開閉原則稍微晦澀一些,因此在開發中容易誤用,因此我們特別要注意類之間是否存在繼承關系。

前面幾篇文章,我們介紹了 SOLID原則的單一職責原則開閉原則,單一職責描述的模塊需要對一類行為負責,開閉原則描述的是對擴展開放,對修改關閉。今天我們就來聊聊SOLID的第三個原則:Liskov替換原則。

什么是里式替換原則?

里式替換原則,Liskov substitution principle(簡稱LSP),它是以作者 Barbara Liskov(一位美國女性計算機科學家,對編程語言和分布式計算做出了開創性的貢獻,于2008年獲得圖靈獎)的名字命名的,Barbara Liskov 曾在1987年的會議主題演講“數據抽象”中描述了子類型:

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替換原則的核心:設Φ(x)是關于 T類型對象 x的可證明性質。那么對于 S類型的對象 y,Φ(y)應該為真,其中 S是 T的子類型。

這種科學的定義是不是過于抽象,太燒腦了?因此,在實際軟件開發中的 Liskov替換原則可以這樣:

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.

該原則定義了在不破壞應用程序的前提下,超類的對象應該可以被其子類的對象替換,這就要求子類對象的行為方式與您的超類對象相同。

Robert C. Martin 對SLP的描述更加直接:

Subtypes must be substitutable for their base types.

子類型必須可以替代它們的基本類型。

通過上面幾個描述,我們可以把 LSP通俗的表達成:子類型必須能夠替換其父類。

如何實現Liskov替換原則?

說起 Liskov替換原則的實現,就不得不先看一個著名的違反 LSP設計案例:正方形/長方形問題。盡管這個 case已經有點老掉牙,但是為了幫助理解,我們還是炒一次剩飯。

數學知識告訴我們:正方形是一種特殊的長方形,因此用 java代碼分別定義 Rectangle(長方形) 和 Square(正方形)兩個類,并且 Square繼承 Rectangle,代碼如下:

// Rectangle(長方形)
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 {
    // 設置邊長
    @Override
    public void setLength(double length) {
        super.setLength(length);
        super.setWidth(length);
    }

    @Override
    public void setWidth(double width) {
        super.setLength(width);
        super.setWidth(width);
    }
}

假設現在的需求是計算幾何圖形的面積,因此面積計算代碼會如下實現:

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

在這個例子中,Square類重寫了 setLength和 setWidth方法,以確保正方形的長度和寬度總是相等的。因此:假設 length=3,width=4

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

如何解決這個 bad case呢?

可以定義一個幾何圖形的接口,設定一個計算面積的方法,然后長方形、正方形都實現這個接口,實現各自的面積計算邏輯,整體思路如下:

// 基類
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;
    }
}

我們再來看一個 LSP使用的例子:

假設有一個股票交易的場景,而且需要支持債券、股票和期權等不同證券類型的多種交易類型,我們就可以考慮使用 LSP來解決這個問題。

首先,我們定義一個交易的基類,并且在基類中定義買入和賣出兩個方法實現,代碼如下:

// 定義一個交易類
public class Transaction{
    // 買進操作
    public void buy(String stock, int quantity, float price){
        
    }

    // 賣出操作
    public void sell(String stock, int quantity, float price){
        
    }
}

接著,定義一個子類:股票交易,它和基類具有相同的買入和賣出行為,因此,在股票交易子類中需要重寫基類的方法,代碼如下:

// 定義股票交易子類,定義股票特定的買賣動作邏輯
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){
       
    }
}

同樣,定義一個子類:基金交易,它和基類具有相同的買入和賣出行為,因此,在基金交易子類中需要重寫基類的方法,代碼如下:

// 定義基金交易子類,定義基金特定的買賣動作邏輯
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){
       
    }
}

同樣,我們還可以定義了債券交易子類,債券交易和交易基類具有相同的行為:買入和賣出。所以只需要重寫基類的方法,實現子類特定的實現就ok了。

// 定義債券交易子類,定義債券特定的買賣動作邏輯
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){
        
    }
}

上述交易的案例,股票交易和基金交易子類替換基類之后,并沒有破壞基類的買入賣出行為,更具體地說,替換的子類實例仍提供 buy()和 sell(),可以以相同方式調用的功能。這個符合LSP。

經過我們的抽象、分離和改造之后,Stock.updateStock()類就穩定下來了,再也不需要增加一個事件然后增加一個else if分支處理。這種抽象帶來的好處也是很明顯的:每次有新的庫存變更事件,只需要增加一個實現類,其他的邏輯都不需要更改,當庫存事件無效時只需要把實現類刪除即可。

總結

Liskov替換原則擴展了OCP開閉原則,它描述的子類型必須能夠替換其父類型,而不會破壞應用程序。因此,子類需要遵循以下規則:

  • 不要對輸入參數實施比父類實施更嚴格的驗證規則。
  • 至少對父類應用的所有輸出參數應用相同的規則。

Liskov替換原則相對前面的單一職責和開閉原則稍微晦澀一些,因此在開發中容易誤用,因此我們特別要注意類之間是否存在繼承關系。

LSP不僅可以用在類關系上,也可以應用在接口設計中。

責任編輯:趙寧寧 來源: 猿java
相關推薦

2024-05-06 09:41:54

TypeScriptextends類型兼容

2012-03-05 13:58:34

設計模式里氏置換

2024-07-11 16:32:13

代碼Java

2021-06-17 22:48:41

McAfee

2021-03-16 08:35:14

Kubernetes Docker容器

2023-12-08 07:59:41

對象設計設計模式軟件設計

2010-07-19 14:00:30

Telnet服務

2009-06-11 11:54:00

GlassFishTomcat

2010-09-28 16:22:23

SQL ntext字段

2011-04-18 09:01:45

CSSHTML

2010-09-26 10:35:47

sql替換語句

2023-09-22 16:28:34

C++編程

2018-11-12 13:54:37

Web圖片替換 網頁加速

2010-07-15 17:56:08

2021-08-30 23:47:28

URLQuery字段

2010-06-29 11:12:46

WiMAX

2021-05-10 11:53:13

頁面替換算法

2010-09-28 15:54:55

SQL替換字段

2010-09-26 10:27:22

SQL替換語句

2015-10-26 13:16:11

FreeMarkerJSP
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人精品一区二区三区中文字幕 | 一区二区三区四区不卡 | 日韩国产中文字幕 | 国产精品日韩一区二区 | 精品久久久久久久 | 毛片免费在线 | 97色在线观看免费视频 | 国产成人99久久亚洲综合精品 | 精品免费国产一区二区三区四区介绍 | 欧美一区二区三区国产精品 | 国产成人综合在线 | 黄色成人亚洲 | 亚洲国产成人av好男人在线观看 | 精品一区二区三区中文字幕 | 亚洲九九色 | 99久久国产综合精品麻豆 | 精品1区2区| 91视视频在线观看入口直接观看 | 日本精品视频在线 | 天天操天天操 | 亚洲综合在线播放 | 久久黄色精品视频 | 国产精品精品3d动漫 | 欧美成人免费电影 | 国产精品一区久久久 | 亚洲人在线播放 | 午夜影院在线观看 | 免费一区| 噜噜噜噜狠狠狠7777视频 | 成人毛片视频免费 | 亚洲国产成人精品久久久国产成人一区 | 欧洲高清转码区一二区 | 91免费观看国产 | 毛片免费观看视频 | 国产一二区视频 | 亚洲精品久久久久久首妖 | 东方伊人免费在线观看 | 欧美一二三| 欧美男人的天堂 | 国产成人精品久久久 | 亚洲精品99|