リスコフ置換原理

PHPz
リリース: 2024-08-25 22:30:36
オリジナル
1142 人が閲覧しました

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() をオーバーライドしますが、未実装のままにしておきます。これは、レーシング カーにはキャビン幅がないためです (F1 レーシング カーを見ると、内部スペースがありません。あるのはドライバーが座るコックピットだけです)
したがって、レーシングカーの室内空間はコックピットと呼ばれます。
注: レーシングカーには一般的な車と一致しない仕様がある可能性があります

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 ループは 3 回目の反復で失敗するため、これは公開されたデザインです。
これを修正するには、継承そのものであるルートを攻撃する必要があります。


解決策 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: 聞かないで伝える

Amazon の別の例を見てみましょう
Amazon では、すべてのサードパーティ製品に対して x 額の割引を提供しています。
すべての自社製品を 1.5 倍で提供します (Amazon ベーシック 製品は Amazon の自社製品です)

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 ステートメントは、Liskov 置換原則に反します InHouseProduct の割引額の更新に関係していることに注意してください (オブジェクト Product をそのサブタイプ InHouseProduct に置き換えることができたはずです)。 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 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート