“这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战”
一、Liskov Substitution Principle里氏替换原则
(一)、里氏替换原则定义
里氏替换原则是指如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
简单来说便是,继续必须确保超类所拥有的性质在子类中仍然成立。
子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。 子类中可以增加自己特有的方法。 当子类重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
(二)、里氏替换原则优点
(1)、里氏替换原则是实现开闭原则的重要方式之一。
(2)、它克服了继承中重写父类造成的可复用性变差的缺点。
(3)、它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
(三)、案例代码
1、不符合里氏替换原则的情况
长方形的类:
public class Rectangle {
private long width;
private long height;
public long getWidth() {
return width;
}
public void setWidth(long width) {
this.width = width;
}
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
}
正方形的类:继承了长方形,并且改变了长方形的方法
public class Squre extends Rectangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getWidth() {
return length;
}
@Override
public void setWidth(long width) {
setLength(width);
}
@Override
public long getHeight() {
return length;
}
@Override
public void setHeight(long height) {
setLength(height);
}
}
错误情况:检查长方形的长是否大于宽,如果没有就需要加1直到长大于宽,但是因为正方形是长方形的子类,所以传正方形的类依然可以成立,但是方法执行是死循环因为长和宽永远相等。
public class Check {
public void resize(Rectangle rectangle){
while(rectangle.getWidth()>=rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight()+1);
System.out.println("长"+rectangle.getHeight()+"宽"+rectangle.getWidth());
}
System.out.println("长"+rectangle.getHeight()+"宽"+rectangle.getWidth());
}
public static void main(String[] args) {
Squre squre = new Squre();
squre.setLength(10);
Check check = new Check();
check.resize(squre);
}
}
2、里氏替换原则的方法的前置条件的范围不同的区别
当子类重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。可以自己通过写代码验证
你会发现执行结果依然是父类的,但一旦你的前置条件比父类方法更严格就相当于是子类的方法,执行的方法不同。子类可以扩展方法但不得重写或覆盖已经实现的方法
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。这个当你用代码实现的时候如果不满足此条件编译器都会报错。
public class Parent {
public void method(HashMap hashMap){
System.out.println("父类方法执行");
}
}
public class Son extends Parent{
public void method(Map hashMap) {
System.out.println("子类方法执行");
}
public static void main(String[] args) {
Son son = new Son();
HashMap hashMap = new HashMap();
son.method(hashMap);
}
}
二、Composite&Aggregate Reuse Principle合成复用原则
(一)、合成复用原则定义
合成复用原则是指尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的,可以使得系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
继承称之为白箱复用,相当于把所有的细节都暴露给子类。组合/聚合称之为黑箱复用,对类之外的对象是无法获取到细节的。
(二)、合成复用原则优点
(1)、它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
(2)、新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。
(3)、复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。
(三)、案例代码
public interface DBconnect {
String getConnect();
}
public class MysqlConnect implements DBconnect {
public String getConnect() {
return "mysql连接";
}
}
public class ProductConnect {
private DBconnect dBconnect ;
public void setdBconnect(DBconnect dBconnect) {
this.dBconnect = dBconnect;
}
public void addConnect(){
System.out.println(dBconnect.getConnect());
}
public static void main(String[] args) {
ProductConnect productConnect = new ProductConnect();
productConnect.setdBconnect(new MysqlConnect());
productConnect.addConnect();
}
}