里氏代换原则__设计模式七大原则

一、原则

Liskov于1987年提出关于继承的原则:继承必须确保超类所拥有的性质在子类中仍然成立。
也就是说,当一个子类的实例能够替换任何其超类的实例时,它们之间才具有is-A关系。该原则称为里氏代换原则:子类型(subtype)必须能够替换它们的基(父)类型。 即子类可以以父类的身份出现。
里氏代换原则是关于继承机制的原则,是实现开放-封闭原则的具体规范,违反了里氏代换原则必然违反了开放-封闭原则。

基本介绍
只要有父类出现的地方,都可以使用子类来替代。而且不会出现任何错误或者异常。
但是反过来却不行。子类出现的地方,不能使用父类来替代。

主要作用:
规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖。

例如,如果鸟是会飞的,企鹅不会飞,企鹅是鸟吗?类“鸟”中有个方法fly,企鹅自然也继承了这个方法,可是企鹅不能飞,于是,在企鹅的类中覆盖了fly方法,告诉方法的调用者:企鹅是不会飞的。这完全符合常理。但是,这违反了里氏代换原则(继承必须确保超类所拥有的性质在子类中仍然成立。),企鹅是鸟的子类,可是企鹅却不能飞!

通用的解决思路:
让原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。

注意事项:
里氏代换原则规定,子类不能覆写父类已实现的方法。父类中已实现的方法其实是一种已定好的规范和契约,如果随意修改它,那么可能会带来意想不到的错误。子类中可以增加自己特有的方法(可以随时扩展)子类继承了父类,拥有了父类和方法,同时还可以定义自己有,而父类没有的方法。这是在继承父类方法的基础上进行功能的扩展。

二、举例说明

class A{
    public int func1(int num1, int num2){
        return num1-num2;
    }
}

class B extends A{
    public int func1(int a,int b){ //重写父类代码
        return a+b;}
    public int func2(int a, int b){
        return func1(a,b)+9;}
}

public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" +a.func1(11,3));
        System.out.println("1-8="+a.func1(1,8));
        System.out.println ("-------");
        B b = new B();
        System.out.println("11-3=" + b.func1(11,3));
		//这里本意是求出11-3
        System.out.println("1-8="+ b.func1(1,8));
        System.out.println("11+3+9="+b.func2(11,3));
    }
}

运行结果
11-3=8
1-8=-7
-------
11-3=14
1-8=9
11+3+9=23

分析:
原来运行正常的相减功能发生了错误。原因就是类B重写了父类的方法func1,造成原有功能出现错误。在实际编程中,常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候。

解决思路
遵循里氏代换原则,让原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。

//创建一个更加基础的基类
class Base { //把更加基础的方法和成员写到Base类
}

class A extends Base { // A类
    public int func1(int num1, int num2) { //返回两个数的差
        return num1 - num2; }
}

class B extends Base{
    A a=new A();
    public int func1(int a,int b){
        return a+b; }
    public int func2(int a, int b){
        return func1(a,b)+9; }
    public int func3(int a, int b){
        return this.a.func1(a,b); }
}

public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" +a.func1(11,3));
        System.out.println("1-8="+a.func1(1,8));
        System.out.println ("-------");
        B b= new B();
		//因为B类不再继承A类,因此调用者,不会再func1是求减法
		//调用完成的功能就会很明确
        System. out.println("11+3=" + b. func1(11, 3)); //11+3
        System. out.println("1+8=" + b.func1(1, 8)); // 1+8
        System. out.println("11+3+9=" + b.func2(11, 3));
		//使用聚合仍然可以使用到A类相关方法
        System. out.println("11-3=" + b.func3(11, 3)); // 求11-3
    }
}

运行结果:
11-3=8
1-8=-7
-------
11+3=14
1+8=9
11+3+9=23
11-3=8
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值