【问题标题】:Liskov Substitution Principle and casting [duplicate]Liskov替换原则和铸造[重复]
【发布时间】:2016-01-27 15:50:44
【问题描述】:

我刚刚在(Java)面向对象编程的讲座中遇到了 Liskov 替换原则和强制转换。我明白原理是什么,就是我可以用超类的类型来初始化一个子类:

SuperClass superClass = new SubClass();

我首先关心的是这种操作的目的。为什么我不能像往常一样声明子类(示例如下)?

SubClass subClass = new SubClass();

紧接着,我就卡在了投射上,如下:

SuperClass superClass = new SubClass();
SubClass subClass = (SubClass)superClass;

再一次,我很难理解这一切的意义。

谁能解释这些程序的目的?

【问题讨论】:

    标签: java casting substitution


    【解决方案1】:

    Liskov 替换原则意味着子类应该在理解的情况下完成,您应该真正关心实例在实例化时是什么子类。从那时起,它应该像超类一样被对待,不添加任何方法或特殊处理。

    这种方法的最大优点是,如果您决定要用另一个子类替换一个子类,您可以!它的调用方式与调用前一个子类的方式完全相同。如果这对您的新子类不方便,那么 Liskov 会说这意味着它不应该真正成为该超类的子类。子类应该不分青红皂白地对待。

    关于您的强制转换,当您将 SubClass 分配给 SuperClass 时,您现在有了一个可以在整个程序中使用的实例,而无需关心它是否专门为 SubClass。您尝试将 superClass 实例转换回子类的以下行 can 可以完成,但是您 可能 没有正确地做某事(再次,因为您不应该关心它是什么子类)。

    通常你会看到一个工厂或方法实例化它如下:

    public SuperClass getSuperClass() {
        SubClass subClass = new SubClass();
    
        // Here is the only place where you should perform subclass specific
        // calls.  The less you need to do here, the better.
        subClass.setSubClassProperty(this);
    
        return subClass;
    }
    

    当我返回一个 SubClass 实例并且给调用者一个 SuperClass 实例时,请注意隐式转换为 SuperClass。这就是我们喜欢它的方式。调用者可以接收一个 SubClass 实例,但我们不希望调用者使用 SubClass 方法的诱惑。

    【讨论】:

      【解决方案2】:

      因为这样你可以在不知道任何子类的情况下使用超类方法。考虑下一个例子:

      想象一下可以画出来的东西:

      public abstract class Thing {
         public abstract void draw();
      }
      

      如果你有这些东西的列表,你可以循环绘制它们:

      List<Thing> list = ...
      for(thing: list) {
         thing.draw()
      }
      

      现在你想画实际的东西:圆形、正方形等。所以你写了具体的类:

       public class Circle extends Thing {
            private final Point center;
      
            public Circle(Point center) {
                 this.center = center; 
            }     
      
            public void draw() {
                   //draw a circle in coordinates center
            }
       }
      
       public class Square...
      

      如何创建具体事物的列表?很容易因为超类到子类的概念:

       Thing circle1 = new Circle(10,10);
       Thing square = new Square(0,0,10,10);
       Thing circle2 = new Circle(50,100);
      

      现在将它们添加到列表中并在同一个循环中使用。

       List<Thing> list = new ArrayList<>();
       list.addAll(square, circel1, circle2);
      
       for( thing: list) {
          thing.draw()
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-05
        • 2010-12-03
        • 2019-10-29
        • 2016-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多