首頁  >  文章  >  Java  >  里氏替換原則

里氏替換原則

PHPz
PHPz原創
2024-08-25 22:30:361110瀏覽

Liskov Substitution Principle

物件應該可以替換為其子類型,而不影響程式碼的正確性

讓我們透過繼承來理解這一點(Is-a 關係)
例如:鴕鳥是鳥,駝背是汽車等

範例:賽車是一輛車

public class Car{
    public double getCabinWidth(){
        //return cabin width
    }
}
public class RacingCar extends Car{
    @Override
    public double getCabinWidth(){
        //UNIMPLEMENTED
    }
    public double getCockpitWidth(){
        //return the cockpit width of the racing car
    }
}

RacingCar 覆蓋了汽車類的getCabinWidth() 但保留它未實現因為賽車沒有駕駛室寬度(如果你看到一輛一級方程式賽車,它沒有任何內部空間,它所擁有的只是一個駕駛坐的駕駛艙)
因此賽車的內部空間稱為駕駛艙。
注意:賽車的一些規格可能與通用汽車不符

public class CarUtil{
    Car car1 = new Car();
    Car car2 = new Car();
    Car car3 = new RacingCar();

    List<Car> myCars = new ArrayList<>();
    myCars.add(car1);
    myCars.add(car2);
    myCars.add(car3);
    // this will not work in 3rd iteration, because the getCabinWidth() in RacingCar is not implemented 
    for(Car car  : myCars){
        System.out.println(car.getCabinWidth());
    }
}

這是一個已經公開的設計,因為 for 迴圈將在第三次迭代時失敗。
為了解決這個問題,我們必須直擊根源,也就是繼承本身。


解 1:(打破層次結構

我們必須打破繼承,相反,我們將為 Car 和 RacingCar 提供一個共同的父對象

我們將建立一個非常通用的父類,名為 Vehicle

public class Vehicle{
    public double getInteriorWidth(){
        //return the interior width
    }
}
public class Car extends Vehicle{
    @Override
    public double getInteriorWidth(){
        return this.getCabinWidth();
    }
    public double getCabinWidth(){
        //return cabin width
    }
}
public class RacingCar extends Vehicle{
    @Override
    public double getInteriorWidth(){
        return this.getCockpitWidth();
    }

    public double getCockpitWidth(){
        //return the cockpit width of the racing car
    }
}
public class VehicleUtils{
    Vehicle vehicle1 = new Car();
    Vehicle vehicle2 = new Car();
    Vehicle vehicle2 = new RacingCar();

    List<Vehicle> vehicles = new ArrayList<>();
    vehicles.add(vehicle1);
    vehicles.add(vehicle2);
    vehicles.add(vehicle3);
    for(Vehicle vehicle : vehicles){
        System.out.println(vehicle.getInteriorWidth());
    } 
}

**打破層次結構:若替換失敗則打破層次結構


解答 2:只告訴不要問

我們再舉一個亞馬遜的例子
亞馬遜對所有第三方產品提供 x 折扣。
並對所有自營產品提供1.5倍x優惠(Amazon Basics產品均為亞馬遜自營產品)

public class Product{
    public double discount = 20;//x amount of discount on all the third-party products on Amazon
    public double getDiscount(){
        return discount;
    }
}
public class InHouseProduct extends Product{
    public void applyDiscount(){
        discount  = discount*1.5;// 1.5 times more discount on InHouseProducts
    }
}
public class PricingUtils{
    Product p1 = new Product();
    Product p2 = new Product();
    Product p2 = new InHouseProduct();
    List<Product> products = new ArrayList<>();
    products.add(p1);
    products.add(p2);
    products.add(p2);
    for(Product product : products){
        if(product instanceOf InHouseProduct){
            ((InHouseProduct)product).applyDiscount();
        }
        System.out.println(product.getDiscount());
    }
}

請注意,if 語句涉及更新InHouseProduct 的折扣金額,這違反了里氏替換原則(因為我們應該能夠用其子類型InHouseProduct 替換對象Product),但是這裡在if 語句中,我們手動更新折扣金額,這是不應該執行的。

對 InHouseProduct 類別進行輕微修改即可解決此問題

public class InHouseProduct extends Product{

    @Override
    public double getDiscount(){
        applyDiscount();
        return discount;
    }
    public void applyDiscount(){
        discount  = discount*1.5;
    }
}

最後從 PricingUtils 類別中刪除 if 語句

public class PricingUtils{
    Product p1 = new Product();
    Product p2 = new Product();
    Product p2 = new InHouseProduct();
    List<Product> products = new ArrayList<>();
    products.add(p1);
    products.add(p2);
    products.add(p2);
    for(Product product : products){
        System.out.println(product.getDiscount());
    }
}

告訴不要問:這裡我們告訴utils 類打印所有折扣,並且utils 類不必詢問任何內容(因為它是通過if 來詢問的)之前聲明)


以上是里氏替換原則的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:介面隔離原則下一篇:介面隔離原則