尝试理解里氏替换原理

rai*_*yan 4 java solid-principles

我试图理解里氏替换原则,我有以下代码:

class Vehicle {
}

class VehicleWithDoors extends Vehicle {
    public void openDoor () {
        System.out.println("Doors opened.");
    }
}

class Car extends VehicleWithDoors {
}

class Scooter extends Vehicle {
}

class Liskov {
    public static void function(VehicleWithDoors vehicle) {
        vehicle.openDoor();
    }

    public static void main(String[] args) {
        Car car = new Car();
        function(car);
        Scooter scooter = new Scooter();
        //function(scooter);  --> compile error
    }
}

Run Code Online (Sandbox Code Playgroud)

我不确定这是否违反。原则上说,如果你有一个类 S 的对象,那么你可以用类 T 的另一个对象替换它,其中 S 是 T 的子类。但是,如果我写怎么办

Vehicle vehicle = new Vehicle();
function(vehicle);
Run Code Online (Sandbox Code Playgroud)

这当然会产生编译错误,因为 Vehicle 类没有 openDoor() 方法。但这意味着我不能用它们的父类Vehicle来替换VehicleWithDoors对象,这似乎违反了原则。那么这段代码是否违反了呢?我需要一个很好的解释,因为我似乎无法理解它。

pla*_*alx 5

你搞反了。该原则指出“如果S是 的子类型T,则T程序中的 类型的对象可以用 类型的对象替换,S而不改变该程序的任何所需属性”。

基本上, VehicleWithDoors应该在能Vehicle工作的地方工作。这显然并不意味着Vehicule应该在工作的地方工作VehiculeWithDoors。但换句话来说,您应该能够用专门化代替概括,而不影响程序的正确性。

示例违规是扩展定义操作的ImmutableLista ,其中不可变实现抛出异常。Listadd

class List {
  constructor() {
    this._items = [];
  }
  
  add(item) {
    this._items.push(item);
  }
  
  itemAt(index) {
    return this._items[index];
  }
}

class ImmutableList extends List {
  constructor() {
    super();
  }
  
  add(item) {
    throw new Error("Can't add items to an immutable list.");
  }
}
Run Code Online (Sandbox Code Playgroud)

接口隔离原则 (ISP) 可用于避免此处声明ReadableList接口的冲突WritableList。

传达可能不支持添加项目的另一种方式可能是添加canAddItem(item): boolean方法。设计可能不那么优雅,但它清楚地表明并非所有实现都支持该操作。

我实际上更喜欢 LSP 的这个定义:“LSP 表示每个子类必须遵守与超类相同的契约”。“合同”不仅可以在代码中定义(在我看来更好),还可以通过文档等来定义。

  • 不可变列表是一个非常好的违规示例 (2认同)