物件應該可以替換為其子類型,而不影響程式碼的正確性
讓我們透過繼承來理解這一點(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中文網其他相關文章!