• LSP原则—关于正方形不是长方形


    长方形有二个属性长和宽。并有一个设置长的方法和设置宽的方法,还有一个求面积的方法. 
    像下面 
    private int length; 
    private int width; 
    public void setLength(int lenght) { 
    this.length = lenght; 

    public void setWidth(int width) { 
    this.width= width; 

    public int getArea() { 
    return this.length * this.width; 

    如果说正方形是长方形的子类。为了保证正方形长和宽相等,那对应于正方形的二设置长宽的个方法就得改成 
    public void setLength(int lenght) { 
    this.length = lenght; 
    this.width= lenght; 

    public void setWidth(int width) { 
    this.length = width; 
    this.width= width; 

    那我们想想用户使用时候的情景。 我们都知道长方形的面积等于长与宽的积。那当我们用长方形的时候我们会这样用 
    Rectangle rectangle = new Rectangle(); 
    rectangle.setLength(5); 
    rectangle.setWidth(4); 
    我们想知道面积是多少我们就可以 
    rectangle.getArea(); 
    得到的是20,当然结果是非常正确的。 
    但想想如果我们把一个正方形的实例给用户用的时候会怎么样 
    Rectangle rectangle = new Square(); //注意,这里体显代换原则。用户根本不知道真正的实例是正方形,用户只知道长方形的事情。 
    rectangle.setLength(5); 
    rectangle.setWidth(4); 
    我们想知道面积是多少我们就可以 
    rectangle.getArea(); 
    得到的结果却是 16 ,这违背了长方形的面积是长与宽之积的原则。用户就不会明白为什么我设置了长是5宽是4得到的答案却是16 ?? 与前提不符 
    所以正方形不能代替长方形出现在这个地方。 
    也就是说正方形不应当看作是长方形的子类。

     之前人们讨论的正方形长方形的问题的关键在哪里?我觉得就在于改动长方形的边的长度。我们可以这么考虑一下,一个长方形的instance的边长应该是可变的吗?我觉得一旦一个长方形的边长改变之后它就成了另一个长方形了(一个新的instance)。所以长方形类里面不应该有改变其边长的方法,一个长方形实例各个的边长应当在new它的时候确定下来,并且它们应当是immutable的。基于这种考虑,我设计的长方形和正方形的类如下所示:
    //长方形
    public class Rectangle {
      private final int width;
      private final int height;
      
      public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
      }
      
      public int getWidth() {
        return width;
      }

      public int getHeight() {
        return height;
      }
      
      public int getArea() {
        return width*height;
      }
    }

    //正方形
    public class Square extends Rectangle{
      private final int side;
      
      public Square(int side) {
        super(side, side);
        this.side = side;
      }
      
      public int getSide() {
        return side;
      }
    }

            这种继承关系就既符合现实中的父子关系也遵循LSP。之所以这么设计,我的想法是一个类所具有的方法不应当能够改变其本质。比如有一个Men类,它可以有eat(),sleep(),work(),makeLovewith(Person p)方法,但是如果你在里面定义denatureToWomen(),denatureToEunuch()就很不恰当了,因为这改变了其本质,导致这个Men的实例不再属于Men类(至少已经和现实不吻合)了。除非这两个方法不能改变该实例本质,否则在Men里面定义这两个方法本身就是有问题的。

  • 相关阅读:
    Java实现 LeetCode 437 路径总和 III(三)
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 435 无重叠区间
    Java实现 LeetCode 435 无重叠区间
    Makefile第一讲:一个简单的Makefile
    GCC常用参数
    GCC参数详解
    linux .o,.a,.so文件解析
  • 原文地址:https://www.cnblogs.com/jianghengsh/p/11132543.html
Copyright © 2020-2023  润新知