几乎所有的将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;
    }
}

解决方案 »

  1.   

    感觉Martin这人就会把屁话说来说去。目前搞面向对象的所谓大师都是Java发家的,好点的就算对更早期的和复杂的面向对象语言也很熟,可以这么说,他们的局限性是因为他们是程序员起家的。计算机科学的根本在于各种数学上的抽象,而我怀疑象Martin这类人,连与计算机学科关系十分密切的如《算法论》之类都没有好好看过,说白了其真实水平比你我高不到哪里去(当然我也没好好看过)。你说的这个长方形和正方形的例子,继承之时相当于重新定义了语义(其实还可以从很多个更根本的角度来看),这样表面文字上来看是继承,其实根本不是真正的继承关系,自然会产生问题。再从测试来看,这个测试只覆盖了特殊情况,既然这个对象对于测试来说属于黑盒(里面如何变化外部不清楚),那么这个测试本应定义成测试结果是不是等于W乘以H,以求证Area与W和H的关系是前者等于后两者相乘,而并非一个固定用例的测试,而这个测试显然没有做到这一点(因为它的用值并非来自于赋值后重新取出的W和H),所以出错也是自然而然的事。因为它用的并非这些本来都是很自然的事,想不清楚只是经验不够,思维上还没有统一起来形成可以覆盖的高度。现在让这些大师们一顿云山雾罩,事情反而变得玄妙和复杂了,真是SHIT。以上言论不是针对LZ,而是针对绝大多数靠Java的炒作而出书立传发家的大师和专家。=======================================================================
    这是网上高手给出的解答
      

  2.   

    我觉着Robert C. Martin对liskov的简化改变了Barbara Liskov的本意呀
    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
      

  3.   

    这样看来好像是 Robert C.Martin 曲解了里氏替换原则的本意。
      

  4.   

    不知道什么叫“liskov原则”,但《effective C++ 第三版》里面讨论过这个问题 可以参考p154-p155
    其大致的解释为:
    一些可以运用在矩形上的方法(比如单独增加矩形的长或者宽)却不能运用在正方形上(因为正方形必须长和宽一致)。
    简单的说:
    “能够施行于base class对象上的每件事情,也可以施行于derived class对象身上”
      

  5.   

    “能够施行于base class对象上的每件事情,也可以施行于derived class对象身上”
    ____________________________________________________________________________这个就是“里氏替换原则”。
      

  6.   

    每构造一个边长为X的正方形,就可以构造一个长、宽都为X的长方形,使得任何使用这个长方形的地方替换成正方形後,不改变程序的逻辑,因此,正方形继承长方形是符合Barbara Liskov对里氏替换原则的。但是并不是任何一个长方形,都可以找到一个正方形,使得任何使用这个长方形的地方替换成正方形後,不改变程序的逻辑
    因此,正方形继承长方形是不符合Robert C. Martin对里氏替换原则的。所以 觉着Robert C.Martin 曲解了里氏替换原则的本意
      

  7.   

    关键是子类扩展父类的时候,只能增加字段和方法,而不能增加约束。长和宽必须相等是对父类中两个字段的约束,而在子类无法扩展这种约束,这算是目前oo语言的局限性。期待下一代oo语言解决。
      

  8.   

    那么 子类是父类的某种特例,这种情况下是否不应该使用继承呢?因为特例必然是在父类的基础上添加了约束的回复人:cxz7531(大花猫) ( 五级(中级)) 信誉:97  2007-09-06 09:02:22  得分:0
      关键是子类扩展父类的时候,只能增加字段和方法,而不能增加约束。
      长和宽必须相等是对父类中两个字段的约束,而在子类无法扩展这种约束,这算是目前oo语言的  局限性。期待下一代oo语言解决。
      

  9.   

    是否可以这样认为
    Barbara Liskov 提出了LSP原则,
    Robert C. Martin强化了这一原则
    Robert C.Martin的LSP强化版提出了更苛刻的要求,即要求子类不能改变父类的行为,因此也提供了更好的扩展性