几乎所有的将Liskov原则的文章都提到了“正方形继承长方形违反Liskov原则”。
但都说的不清不楚的
假设我有如下的两个类,请问哪个地方违反了Liskov原则呢?
public class Rectangle ...{
protected double width;
protected double height; public double getWidth() ...{
return width;
} public void setWidth(double width) ...{
this.width = width;
} public double getHeight() ...{
return height;
} public void setHeight(double height) ...{
this.height = height;
} public double calcSize() ...{
return this.height * this.width;
}
}public class Square extends Rectangle ...{
@Override
public void setHeight(double height) ...{
setEdge(height);
} @Override
public void setWidth(double width) ...{
setEdge(width);
} @Override
public double getHeight() ...{
return getEdge();
} @Override
public double getWidth() ...{
return getEdge();
} public double getEdge() ...{
return this.height;
} public void setEdge(double edge) ...{
this.height = edge;
this.width = edge;
}
}
但都说的不清不楚的
假设我有如下的两个类,请问哪个地方违反了Liskov原则呢?
public class Rectangle ...{
protected double width;
protected double height; public double getWidth() ...{
return width;
} public void setWidth(double width) ...{
this.width = width;
} public double getHeight() ...{
return height;
} public void setHeight(double height) ...{
this.height = height;
} public double calcSize() ...{
return this.height * this.width;
}
}public class Square extends Rectangle ...{
@Override
public void setHeight(double height) ...{
setEdge(height);
} @Override
public void setWidth(double width) ...{
setEdge(width);
} @Override
public double getHeight() ...{
return getEdge();
} @Override
public double getWidth() ...{
return getEdge();
} public double getEdge() ...{
return this.height;
} public void setEdge(double edge) ...{
this.height = edge;
this.width = edge;
}
}
这是网上高手给出的解答
Liskov的意思是
对于任何子类对象,都有一个父类对象,是的使用此父类对象的程序该为子类对象後行为不变。
但是Robert C.Martin的意思变成了:
对于任何父类对象,都有一个子类对象,是的使用此父类对象的程序该为子类对象後行为不变。Liskov Substitution Principle:
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T." - BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988).以下是Robert C. Martin的简化版:
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it - Robert C. Martin, Engineering Notebook, C++ Report, Nov-Dec, 1996Subtypes must be substitutable for their base types - Robert C. Martin, Agile Software Development Principles Patterns and Practices,2002
其大致的解释为:
一些可以运用在矩形上的方法(比如单独增加矩形的长或者宽)却不能运用在正方形上(因为正方形必须长和宽一致)。
简单的说:
“能够施行于base class对象上的每件事情,也可以施行于derived class对象身上”
____________________________________________________________________________这个就是“里氏替换原则”。
因此,正方形继承长方形是不符合Robert C. Martin对里氏替换原则的。所以 觉着Robert C.Martin 曲解了里氏替换原则的本意
关键是子类扩展父类的时候,只能增加字段和方法,而不能增加约束。
长和宽必须相等是对父类中两个字段的约束,而在子类无法扩展这种约束,这算是目前oo语言的 局限性。期待下一代oo语言解决。
Barbara Liskov 提出了LSP原则,
Robert C. Martin强化了这一原则
Robert C.Martin的LSP强化版提出了更苛刻的要求,即要求子类不能改变父类的行为,因此也提供了更好的扩展性