Oop 也有15个引脚

Oop 也有15个引脚,oop,solid-principles,liskov-substitution-principle,Oop,Solid Principles,Liskov Substitution Principle,但除了机械配合之外,还有其他考虑因素:插头上的电气行为也必须相同。如果旧收音机接头上的针脚1为+12V,则新收音机接头上的针脚1也必须为+12V。如果新收音机的针脚1是“左扬声器输出”针脚,则收音机可能短路或熔断保险丝。这显然违反了LSP 你也可以考虑一个降级的情况:假设你昂贵的收音机死了,你只能负担得起AM收音机。它没有立体声输出,但它有与现有收音机相同的接口。假设该规范的引脚3为左扬声器输出,引脚4为右扬声器输出。如果您的调幅收音机同时在插脚3和4上播放单声道信号,您可以说它的行为是一致的,

但除了机械配合之外,还有其他考虑因素:插头上的电气行为也必须相同。如果旧收音机接头上的针脚1为+12V,则新收音机接头上的针脚1也必须为+12V。如果新收音机的针脚1是“左扬声器输出”针脚,则收音机可能短路或熔断保险丝。这显然违反了LSP


你也可以考虑一个降级的情况:假设你昂贵的收音机死了,你只能负担得起AM收音机。它没有立体声输出,但它有与现有收音机相同的接口。假设该规范的引脚3为左扬声器输出,引脚4为右扬声器输出。如果您的调幅收音机同时在插脚3和4上播放单声道信号,您可以说它的行为是一致的,这将是一个可接受的替代。但是,如果您的新AM收音机仅在引脚3上播放音频,而在引脚4上不播放音频,则声音会不平衡,这可能不是一个可接受的替代品。这种情况也会违反LSP,因为虽然您可以听到声音,而且没有保险丝熔断,但收音机不符合接口的全部规格。

图像我想在搬家时租车。我给租赁公司打电话,问他们有什么型号。但他们告诉我,我将得到下一辆可用的汽车:

public class CarHireService {
    public Car hireCar() {
        return availableCarPool.getNextCar();
    }
}
但他们给了我一本小册子,告诉我他们所有的车型都有以下特点:

public interface Car {
    public void drive();
    public void playRadio();
    public void addLuggage();
}
这听起来正是我想要的,所以我订了一辆车,然后高兴地离开。在搬家那天,一辆一级方程式赛车出现在我家门口:

public class FormulaOneCar implements Car {
    public void drive() {
        //Code to make it go super fast
    }

    public void addLuggage() {
        throw new NotSupportedException("No room to carry luggage, sorry."); 
    }

    public void playRadio() {
        throw new NotSupportedException("Too heavy, none included."); 
    }
}
我不高兴,因为他们的宣传手册基本上欺骗了我——一级方程式赛车是否有一个看起来可以装行李但无法打开的假行李箱无关紧要,这对搬家没用


如果有人告诉我“我们所有的车都是这样做的”,那么给我的任何车都应该这样做。如果我不能相信他们手册中的细节,那就没用了。这就是Liskov替换原则的本质。在我看来,要构建LSP,子类型永远不能添加新的公共方法。只有私有方法和字段。当然,子类型可以重写基类的方法。如果子类型有一个basetype没有的公共方法,则不能用basetype替换该子类型。如果将实例传递给客户机的方法,从而接收子类型的实例,但参数的类型是basetype,或者如果您有一个类型basetype的集合,其中subytpes也是其中的一部分,那么您如何调用子类型类的方法,而不使用If语句询问它的类型以及类型是否匹配,对该子类型执行强制转换,以便对其调用方法

谢谢你,斯图尔特。给定IVehicle接口,您可能有一辆汽车、一辆卡车和一辆摩托车,每个都实现了该接口。汽车和卡车应采用开门法,而摩托车不应采用开门法。您将如何处理此场景以符合LSP?@random512可能会创建一个具有相同参数和返回类型的函数…并让它不执行任何操作。检查此答案:@geogegeschwend-我不久前更新了答案,以包含OP的第二个问题re
OpenDoors
。但是,橡皮图章的方法是滥用设计的一个明显迹象——我们试图使一些东西“适合”或“符合”一个界面,但在这种情况下并不适用@另一个Dave给出了另一个橡胶捣固的好例子。@StuartLC对不起,我对Liskov校长有点生疏。在观看了鲍勃·马丁讨论固体的一段非常好的视频后,有一种感觉,这个原则如果被用作“测试”。就像一个具有openDoor()函数(行为)的车辆基类,您试图让没有门的摩托车继承它。。。这违反了Liskov替换原理。即使在现实世界中,将摩托车视为车辆也是可以接受的,但在面向对象建模中,情况可能并非如此。那怎么办呢?不要让摩托车继承自汽车。@Henrique这一切都是为了不“欺骗”多态设计。设计接口,并按预期使用。如果这是你的意思,你不能覆盖子类中的虚拟或抽象受保护的属性,并将作用域更改为public。这实际上是接口隔离原则的一个例子,不是吗?接口隔离原则可以从另一个角度解决这个问题(因为接口不会做出具体类无法兑现的承诺)通过分析我可以得出的结论:您必须实现契约(接口)中的方法,也就是说,不允许出现异常。@karlihnos我认为这比你是否抛出异常的级别更高-作为客户机,你应该能够依赖子类作为其父类的实例。子类应该提供更多的功能,或不同的实现,但不应该删除我们知道的关于p的真实内容arent类。也就是说,
NotSupportedException
和类似的异常肯定有破坏LSP的味道。我感觉不到它的LSP,因为根据Bob.bold叔叔的说法,“使用指向或引用基类的函数必须能够在不知道的情况下使用派生类的对象。”我们不使用这个概念(在本例中)不管怎样,你可以重新检查你的答案看看StuartLC于2013年12月31日17:40发布的帖子,你会注意到与我相同的观点。Stuart提到,应该避免访问子类中可用的额外功能的接口降级。为什么?因为它违反了LSP。LSP指的是类,而不是类型和ad将一个新的公共方法绑定到一个子类是完全正确的。
public abstract class Vehicle
{
    public virtual void Drive(int miles)
    {
        Assert(miles > 0 && miles < 300); // Consumers see this as the contract
    }
 }

 public class Scooter : Vehicle
 {
     public override void Drive(int miles)
     {
         Assert(miles > 0 && miles < 50); // ** Violation
         base.Drive(miles);
     }
 }
class ToyCar : IVehicle
{
    public void Drive(int miles) { /* Show flashy lights, make random sounds */ }
    public void FillUpWithFuel() {/* Again, more silly lights and noises*/}
    public int FuelRemaining {get {return 0;}}
}
[Theory]
void EnsureThatIVehicleConsumesFuelWhenDriven(IVehicle vehicle)
{
    vehicle.FillUpWithFuel();
    Assert.IsTrue(vehicle.FuelRemaining > 0);
    int fuelBeforeDrive = vehicle.FuelRemaining;
    vehicle.Drive(20); // Fuel consumption is expected.
    Assert.IsTrue(vehicle.FuelRemaining < fuelBeforeDrive);
}
public class CarHireService {
    public Car hireCar() {
        return availableCarPool.getNextCar();
    }
}
public interface Car {
    public void drive();
    public void playRadio();
    public void addLuggage();
}
public class FormulaOneCar implements Car {
    public void drive() {
        //Code to make it go super fast
    }

    public void addLuggage() {
        throw new NotSupportedException("No room to carry luggage, sorry."); 
    }

    public void playRadio() {
        throw new NotSupportedException("Too heavy, none included."); 
    }
}