uml结构图讲解(概述耦合UML)
uml结构图讲解(概述耦合UML)① 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法对照简单的代码来看一下,就一目了然了这里我们主要谈一下,继承带来的问题:里氏替换原则说简单一点就是:它认为,只有当子类可以替换父类,同时程序功能不受到影响,这个父类才算真正被复用其核心主要有这么四点内容:
小结:
- 我们希望开发刚开始就知道可能发生的变化,因为等待发现变化的时间越长,要抽象代码的代价就越大
- 不要刻意的去抽象,拒绝不成熟的抽象和抽象本身一样重要
定义:继承必须确保超类所拥有的性质在子类中仍然成立
里氏替换原则,主要说明了关于继承的内容,明确了何时使用继承,亦或使用继承的一些规定,是对于开闭原则中抽象化的一种补充
这里我们主要谈一下,继承带来的问题:
- 继承是侵入性的,子类继承了父类,就必须拥有父类的所有属性和方法,降低了代码灵活度
- 耦合度变高,一旦父类的属性和方法被修改,就需要考虑子类的修改,或许会造成大量代码重构
里氏替换原则说简单一点就是:它认为,只有当子类可以替换父类,同时程序功能不受到影响,这个父类才算真正被复用
其核心主要有这么四点内容:
- ① 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- ② 子类中可以增加自己特有的方法
- ③ 当子类的方法重载父类的方法时,子类方法的前置条件(即方法的输入参数)要比父类的方法更宽松
- ④ 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
对照简单的代码来看一下,就一目了然了
① 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
前半句很好理解,如果不实现父类的抽象方法,会编译报错
后半句是这里的重点,父类中但凡实现好的方法,其实就是在设定整个继承体系中的一系列规范和默认的契约,例如 鸟类 Bird 中,getFlyingSpeed(double speed) 用来获取鸟的飞行速度,但几维鸟作为一种特殊的鸟类,其实是不能飞行的,所以需要重写继承的子类方法 getFlyingSpeed(double speed) 将速度置为 0 ,但是会对整个继承体系造成破坏
虽然我们平常经常会通过重写父类方法来完成一些功能,同样这样也很简单,但是一种潜在的继承复用体系就被打乱了,如果在不适当的地方调用重写后的方法,或多次运用多态,还可能会造成报错
我们看下面的例子:
父类 Father
public class Father {
public void speaking(String content){
System.out.println("父类: " content);
}
}
复制代码
子类 Son
public class Son extends Father {
@Override
public void speaking(String content) {
System.out.println("子类: " content);
}
}
复制代码
子类 Daughter
public class Daughter extends Father{
}
复制代码
测试类 Test
public class Test {
public static void main(String[] args) {
// 直接调用父类运行的结果
Father father = new Father();
father.speaking("speaking方法被调用");
// Son子类替换父类运行的结果
Son son = new Son();
son.speaking("speaking方法被调用");
// Daughter子类替换父类运行的结果
Daughter daughter = new Daughter();
daughter.speaking("speaking方法被调用");
}
}
复制代码
运行结果:
父类: speaking方法被调用 子类: speaking方法被调用 父类: speaking方法被调用
② 子类中可以增加自己特有的方法
这句话理解起来很简单,直接看代码
父类 Father
public class Father {
public void speaking(String content){
System.out.println("父类: " content);
}
}
复制代码