目录
[1. 替换性](#1. 替换性)
[2. 行为一致性](#2. 行为一致性)
[3. 不缩减功能](#3. 不缩减功能)
[4. 接口和抽象类](#4. 接口和抽象类)
[6. 代码重用性](#6. 代码重用性)
三、举例说明
里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一种基本原则,是SOLID原则中的第二个。这个原则的核心思想是:如果对于某个类型的对象 TT,能够用 SS 的对象替换 TT 的对象而程序的行为没有改变,那么 SS 必须是 TT 的子类型。
一、理论
里氏替换原则强调的是子类和父类之间的关系,确保子类能够完全替代父类,而不会影响到程序的正确性和功能。换言之,子类应该扩展父类的功能,而不应该缩减其功能。
二、要点
1. 替换性
子类的对象可以替换父类的对象,且不改变程序的正确性。程序处理父类对象的地方能够 transparently 处理任何其子类的对象。
2. 行为一致性
子类应当实现父类的方法,并且应该符合父类的方法预期。在替换时,子类不能返回意外结果、抛出异常或改变父类方法的本质行为。
3. 不缩减功能
子类不能减少父类提供的功能。如果子类不支持某些父类功能,应该将其置于更高的层次结构中。
4. 接口和抽象类
使用接口或者抽象类来定义可替换类型,通过明确的契约确保子类的行为符合预期。
5.避免异常
子类不应抛出父类未约定的异常。如果在父类中没有定义某种异常,那么对应子类也不应该抛出。
6. 代码重用性
遵循该原则可以提高代码的重用性,降低耦合,增强模块的独立性。
三、举例说明
假设有一个父类Bird和一个子类Penguin
java
class Bird {
public void fly() {
System.out.println("I can fly");
}
}
class Sparrow extends Bird {
@Override
public void fly() {
System.out.println("I am a sparrow and I can fly");
}
}
class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Penguins can't fly");
}
}
在这个例子中,Penguin是 Bird的子类,但它不具备飞行的能力。如果在代码中用 Penguin替换 Bird,会导致程序抛出异常,违反了里氏替换原则。
为了遵循里氏替换原则,我们可以使用接口或者抽象类:
java
interface Bird {
void eat();
}
interface FlyingBird extends Bird {
void fly();
}
class Sparrow implements FlyingBird {
@Override
public void eat() {
System.out.println("Sparrow is eating");
}
@Override
public void fly() {
System.out.println("Sparrow is flying");
}
}
class Penguin implements Bird {
@Override
public void eat() {
System.out.println("Penguin is eating");
}
}