处理违反Liskov替代原则的类别'使用方法重载

时间:2015-04-29 22:45:23

标签: java oop inheritance polymorphism

假设我有以下课程:

public class MyClass {

    /* Note: Timestamp extends date */
    public doSomething(java.sql.Timestamp timestamp){
        System.out.println("Timestamp");
        ...
    }

    public doSomething(java.util.Date date){
        System.out.println("Date");
        ...
    }
}

假设我现在运用我的代码:

MyClass myClass = new MyClass();

Date realDate = new Date();
Timestamp timestamp = new Timestamp(0);
Date casted = new Timestamp(0);

myClass.doSomething(realDate);      // prints Date
myClass.doSomething(timestamp);     // prints Timestamp
myClass.doSomething(casted);        // prints Date!!!!!  What?!

我遇到的问题是,由于casted实际上不是日期,因此当我使用它时它不起作用。

除此之外:一般来说,不起作用的子类不应该成为问题,但是时间戳的javadoc说:

  

由于Timestamp类和上面提到的java.util.Date类之间存在差异,因此建议代码不要将Timestamp值一般视为java.util.Date的实例。 Timestamp和java.util.Date之间的继承关系实际上表示实现继承,而不是类型继承。

我知道我可以这样做:

public doSomething(java.util.Date date){
    if(date instanceof type){
        System.out.println("Timestamp");
        ...
    }
    System.out.println("Date");
    ...
}

但这似乎很讨厌。

有没有办法让子类的方法重载工作而不使用巨型switch语句?

编辑:简而言之,似乎Timestamp打破了Liskov substitution principle - 正如@Mick Mnemonic所指出的那样。

1 个答案:

答案 0 :(得分:1)

是的。不是你的错误。这是java.util.Datejava.sql.DateTimestamp的设计怪癖。 (不要对它们太过刻薄。java.util.Date现在已经二十岁了;当他们设计API时,他们仍然在弄清楚这些东西。)如果你直接使用这些类型,没有什么好办法。

一种方法是避免使用这些类,除非您需要,在与需要它们的API的边界处,并在其他地方使用更好设计的日期时间类型集。在您的数据访问层中,必要时使用Timestamp的特殊情况instanceof等。并将所有内容转换为内部代码的Joda-Time(适用于Java 7)或java.time / JSR-310(适用于Java 8)类型。 (如果在Java 7中实际需要纳秒精度,则需要使用自己的Timestamp对象来使用Joda-Time类型。不难;只需确保使用组合而不是像java.util这样的实现继承伙计们!:))你可能会更开心。