【问题标题】:Do abstract properties violate the Liskov substitution principle?抽象属性是否违反 Liskov 替换原则?
【发布时间】:2011-09-09 12:45:08
【问题描述】:

假设我有一个抽象类,例如:

public abstract class Pet {
    private final String name;
    public Pet(String name) { 
        this.name = name 
    };

    public abstract boolean getsSpecialTreatment();
}

public final class Dog extends Pet {
    @Override public boolean getsSpecialTreatment() { return true; }
}

public final class Cat extends Pet {
    @Override public boolean getsSpecialTreatment() { return false; }
}

我的程序将根据是否设置了特殊处理标志来区别对待Pets。我的问题是这是否算作违反了 Liskov 替换原则,该原则指出:

[...] 在计算机程序中,如果 S 是 T 的子类型,那么 T 类型的对象可以被 S 类型的对象替换 [...] 而不改变它的任何所需属性程序(正确性、执行的任务等)。

【问题讨论】:

    标签: java oop liskov-substitution-principle


    【解决方案1】:

    这取决于合同。也就是说,使用您的类的代码必须获得一致的行为,无论它使用的是什么类型的派生。

    如果合同规定“getSpecialTreatment”始终返回 true,那么您将在派生类中违反该规定。

    如果合同规定“getSpecialTreatment”返回一个布尔值确定 blabla.,那么您没有违反 LSP。

    如果您引入了基类中不存在的附加约束,则可能违反 LSP。

    【讨论】:

      【解决方案2】:

      首先,强烈反对你对猫的歧视!

      现在,当程序员调用所谓的“Liskov 替换原则”时,他们并不是真正在学术意义上谈论它。我们一定是在某种非正式的、粗俗的、混蛋的意义上使用它。

      那是什么意思?我发现它只不过是要求子类必须符合超类设定的合同。所以真的很无趣。人们引用这句话只是为了炫耀。

      【讨论】:

      • 我个人同意这个反对意见。但是,我同意 L.S.P.,就像软件模式,像“最佳实践”一样,必须以实际的方式应用,而不仅仅是“学术势利小人”
      • 我不关心学术“LSP”。我们应该停止伪装成计算机科学家。
      【解决方案3】:

      没有。程序中对该方法的任何使用都将基于返回值做出后续决策,就像任何其他方法一样。由于该方法存在的本质,任何程序都不应该对其结果做出假设。因此该方法返回值的变化不应该改变程序的属性。

      【讨论】:

        【解决方案4】:

        在这种情况下,这些类的用户可能会写:

        ...
        if (pet.getsSpecialTreatment()) {
            // special treatment
            ...
        } else {
            // normal treatment
            ...
        }
        ...
        

        此代码适用于这两种情况,因此您不会违反 LSP。但是,如果你有

        public class UnknownAnimal extends Pet {
            @Override public boolean getsSpecialTreatment() {
                throw new UnsupportedOperationException("Unknown species"); 
            }
        }
        

        那么您将违反 LSP,因为现有代码在使用 UnknownAnimal 实例时会中断。

        【讨论】:

        • 即使是最后一个例子也不总是违反 LSP。这取决于预期的设计。尽管您更可能想要声明一个检查异常或明确声明该方法可以在 API 文档中抛出一些异常。
        猜你喜欢
        • 2015-01-01
        • 2012-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-17
        • 2020-02-03
        • 1970-01-01
        • 2017-07-04
        相关资源
        最近更新 更多