LSP可替换原则概念
面向对象编程中,为了更合理的使用继承,构造合理的父类型和子类型,有一个重要的概念,那就是LSP可替换原则,又叫里氏替换原则(Liskov Substitution principle)。它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次会议上名为“数据的抽象与层次”的演说中首先提出。里氏替换原则的内容可以描述为: “If S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of T.” 翻译成汉语也就是如果 S 是 T 的子类型,则类型 T 的对象可以替换为类型 S 的对象(即类型 T 的对象可以替换为子类型 S 的任何对象)而不改变 T 的任何所需属性。这就引出了行为子类型的概念。
行为子类型
行为子类型形式化的定义:
1.父类型的属性,子类型也有;
2.父类型能做的事,子类型也能做,并且子类型不能比父类型做得更差;
3.父类型不能做的事,子类型可能能做。
协变和逆变
协变(covariant),如果它保持了子类型序关系。(当A<=B时,f(A)<=f(B)成立)
逆变(contravariant),如果它逆转了子类型序关系。(当A<=B时,f(B)<=f(A)成立)
重写和重载
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同;
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private);
3、重写的方法的返回值必须和被重写的方法的返回一致;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类,不可抛出新的异常;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
6、静态方法不能被重写为非静态的方法(会编译出错)。
重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响。
实现LSP可替换原则的注意要点
1.子类型能增加属性,但不能删除父类中的属性;
2.子类型能增加方法,但不能删除父类中的方法;
3.子类型需要实现抽象类型中的所有未实现的方法(否则编译器报错);
4.子类型可以重写父类的方法,但是不能改变父类的原意(例如add(a,b)方法,父类return a+b,子类不可以return a-b)。
5.子类型中重写的方法的返回类型必须与父类型方法的返回类型相同,或者是父类型方法的返回类型的协变;
6.子类型中重写的方法的参数类型必须与父类型方法的参数类型相同,或者是父类型方法的参数类型的逆变;
7.子类型中重写的方法不能抛出额外的异常,抛出的异常集合只能时父类抛出异常集合的子集。
8.子类型的RI应该不变或者比父类型的RI更强;
9.子类型的前置条件应该不变,或者比父类型的前置条件更弱;
10.子类型的后置条件应该不变,或者比父类型的后置条件更强;
11.在可见性方面,子类型的可见性必须高于父类的可见性,例如父类的方法是public时,子类的相应方法只能时public。