设计模式六大原则-里氏代换原则(2/6)

289 阅读2分钟

里氏代换原则的概念

里氏代换原则官方的解释是说:任何基类可以出现的地方,子类一定可以出现

大白话说就是:子类可以扩展父类的功能,但是不能改变父类原有的功能

再通俗点说就是:子类继承父类时,除添加新的方法完成新的功能以外,尽量不要重写父类的方法

为什么里氏代换原则要求继承父类时不要重写的方法?

继承作为面向对象的三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承时会给程序带来侵入性,程序的可移植性降低了,增加了对象间的耦合性,比如一个类被其他的类继承了,则当这个类要修改时,,就必须要考虑所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。

举个栗子


A类有个方法操作两个数
public class ClassA {

    public int function1(int a, int b) {
        return a - b;
    }
}

B类继承了A类,重写了A类的function1方法,并有自己的方法

这里还是JDK自带提示,实现父类方法必须要加上@Override注解,如果没有这个注解就更难发现了

public class ClassB extends ClassA {

    @Override
    public int function1(int a, int b) {
        return a + b;
    }

    public  int function2(int a, int b) {
        return a * b;
    }
}

此时的B类重写了A类的方法,并且修改了方法原有的逻辑,实现了自己的逻辑

做个测试,简单模拟一下出错场景

public class Test {

    public static void cal(ClassA classA) {
        System.out.println("100-50 = " + classA.function1(100, 50));
    }

    public static void main(String[] args) {
        ClassA classA = new ClassA();
        cal(classA);

        ClassB classB = new ClassB();
        cal(classB);
    }
}

image.png

我们会看到得到的结果完全是不一样的,当然实际的场景当然没这么简单,但由于这样的一个错误而导致的后果往往都是致命的,在庞大的项目调用链中,你需要一直往上点,然后分析代码原有逻辑和出错逻辑,最后解决了问题,但是同时也浪费了大量的时间

下面的例子就是里氏代换原则建议的方式

public class ClassB extends ClassA {

    public int function2(int a, int b) {
        return a * b;
    }

    public int function3(int a, int b) {
        return a + b;
    }
}

public class Test {

    public static void cal(ClassA classA) {
        System.out.println("100-50 = " + classA.function1(100, 50));
    }

    public static void main(String[] args) {
        ClassA classA = new ClassA();
        cal(classA);

        ClassB classB = new ClassB();
        cal(classB);
    }
}

image.png

在不干扰父类原有逻辑的情况下,添加自己的方法,这样在调用的时候也能使用父类的方法,减少了有可能发生的错误