设计模式-里氏替换原则
优点
面向对象的语言继承必不可少的,有如下优点
- 代码共享,减少创建类的工作量
- 提高代码的重用性
- 提高代码的可扩展性
- 提高代码的可扩展性
- 提高产品代码的开放性
- 继承侵入性 只要继承,必须拥有父类的内容
- 降低代码的灵活性,子类必须拥有父类的属性和方法
- 增强耦合性。
提供规范
里氏替换原则,为继承定义规范。
长方形是不是正方形
正方形是一种特殊的长方形,如果将正方形设计为长方形的子类,不符合里氏替换原则
下方有三个类
类图如下
关系如上所示
package demo1;
public class SmartTest {
/*
* 长方形的长增加超过宽
*
* @param r
* */
public void resize(Rectangle r) {
while (r.getHeight() <= r.getWidth()) {
r.setHeight(r.getHeight() + 1);
}
}
}
package demo1;
/*
* 定义一个长方形类
* @author ming
* */
public class Rectangle {
protected long width; // 可以访问基类继承而来的,不能访问基类本身的,对同包内的可见,并且子类也可见
protected long height;
public void setWidth(long width) {
this.width = width;
}
public long getWidth() {
return this.width;
}
public void setHeight(long height) {
this.height = height;
}
public long getHeight() {
return this.height;
}
}
package demo1;
/*
* 定义一个正方形类继承自长方形类
*
* @author ming
*
* */
public class Square extends Rectangle{
public void setWidth(long width, long height) {
this.width = width;
this.height = height;
}
public long getWidth() {
return width;
}
public void setHeight(long height, long width) {
this.height = height;
this.width = width;
}
public long getHeight() {
return height;
}
}
在上面的三块代码中,当调用SmartTest类的resize方法的时候,如果传入的是父类,那么将会可以的,如果传入的是子类,正方形,那么将会不可以的。
即。上方的为长方形行,正方形不行。
所以上面的栗子不符合里氏替换原则。
解决方法,使用继承时,要遵守里氏替换原则,类B继承类A时,不要重写父类A的方法,也不能重载父类A的方法。
如果代码更改如下更改
让其两个都共同定义同一个父类即可
其中最上层的类为两个类的抽象类。
改进如下
package com.ming;
/*
* 定义一个四边形类,只有get方法set方法
* @author ming
* */
public abstract class Quadrangle {
protected abstract long getWidth();
protected abstract long getHeight();
}
package com.ming;
public class Rectangle extends Quadrangle {
private long width;
private long height;
public void setWidth(long width) {
this.width = width;
}
public long getWidth() {
return this.width;
}
public void setHeight(long height) {
this.height = height;
}
public long getHeight() {
return this.height;
}
}
package com.ming;
public class Square extends Quadrangle{
private long width;
private long height;
public void setWidth(long width) {
this.height = width;
this.width = width;
}
public long getWidth() {
return this.,width;
}
public void setHeight(long height) {
this.height = height;
this.width = height;
}
public long getHeight() {
return this.height;
}
}
在上方的图中,由于两个为平级关系,所以父类的地方,换成子类也都可以。
总结
里氏替换原则;父类可以的地方,换成子类也同样可以。
为什么要符合
一个栗子
package com.ming2;
public class A {
public int func1(int a, int b) {
return a-b;
}
}
package com.ming2;
public 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)+100; // 调用func1
}
}
在上方中,如果这样书写
package com.ming2;
public class Client {
public static void main(String[] args) {
B b = new B();
System.out.println(b.func1(100, 50));
}
}
就违反了里氏替换原则,即子类能使用的时候,父类也必须能使用。