2015-04-29 2 views
3

Предположим, у меня есть следующий класс:Обработка классов, которые нарушают «принцип замещения Лисков» с использованием метода перегружать

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 говорит:

Из-за различий между классом 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?


Edit: Короче говоря, кажется, что Timestamp перерывов Liskov substitution principle - как указывал @Mick Mnemonic.

+2

Это ошибка, так как перегрузка метода работает правильно. Перегрузки метода выбираются во время компиляции, а не во время выполнения. –

+0

(Кроме того, это обычно считается серьезным запахом дизайна для 'foo (подтип)', чтобы вести себя иначе, чем 'foo (supertype)', именно по этой причине.) –

+0

@LouisWasserman - я не думаю, что это ** мой * * дизайн ошибка есть. Я считаю, что автором временной метки является автор ошибок. Это и ваше чтение? – sixtyfootersdude

ответ

1

Да. Не ваша ошибка. Это дизайнерская причуда java.util.Date, java.sql.Date и Timestamp. (Не слишком сильно на них. java.util.Date сейчас исполнилось двадцать лет, они все еще рассматривали этот материал, когда они разрабатывали API.) Нет никакого отличного способа обойти его, если вы будете работать непосредственно с этими типами.

Один из подходов состоит в том, чтобы избежать использования этих классов, кроме тех случаев, когда вы должны, на границе с API-интерфейсами, которые их требуют, и использовать более совершенный набор типов даты и времени в другом месте. На вашем уровне доступа к данным, специальный случай Timestamp и т. Д., Используя, при необходимости, instanceof. И конвертируйте все в Joda-Time (для Java 7) или java.time/JSR-310 (для Java 8) для внутреннего кода. (Если вам действительно нужна наносекундная точность в Java 7, вам нужно перевернуть свой собственный объект Timestamp, чтобы идти с типами Joda-Time. Не сложно, просто убедитесь, что вы используете композицию вместо наследования реализации, как это делали java.util!:)) Вы, вероятно, будете счастливее.

Смежные вопросы