Как вызвать переопределенные методы в подклассе? Потенциальный кандидат на рефакторинг - PullRequest
5 голосов
/ 02 ноября 2009

Первоначально у меня была проблема проектирования, когда мне требовалось пять подклассов суперкласса, где все, кроме двух, использовали бы один и тот же универсальный метод выполнения действий, а два других класса потребовали бы специальной обработки. Я хотел избежать написания метода пять раз; два особых случая и три одинаковых.

Таким образом, каждый класс унаследовал SuperClass и его метод doSomething (), и имел переопределение SubClassSpecial1 и SubClassSpecial2 с собственным методом doSomeThing.

Это было все нормально, пока я не написал метод, который выглядел примерно как

void fooBar(SuperClass obj) {
    obj.doSomething()
}

и его можно назвать fooBar( new SubClassSpecial1() );

Проблема в том, что класс времени выполнения переменной obj теперь принадлежит ее суперклассу, и поэтому он будет вызывать методы, определенные в суперклассе. Конечно, я мог бы создать абстрактный метод doSometing () в суперклассе и заставить каждый подкласс реализовывать свою собственную версию, но это дублировало бы код в трех классах. И я хочу избежать этого ...

Я бы потерял любое усиление, которое дает полиморфизм, если бы у меня было много ветвлений через

if(obj.getClass().getName() == "SubClassSpecial1" )  ((SubClassSpecial1) obj).doSomething()K;
else if ...

Так что же мне делать, чтобы сделать дизайн более элегантным и небрежным?

Ответы [ 3 ]

5 голосов
/ 02 ноября 2009

Меня немного смущает эта часть вашего вопроса:

Конечно, я хотел, чтобы каждый объект вызывал свою собственную версию doSomething (), но не смог понять, что для этого нужно объявить obj как один из подклассовых методов. А теперь это беспорядок.

Конечно, объявление не имеет значения, метод doSomething () всегда будет вызываться в соответствии с типом времени выполнения класса.

Так что я думаю, что то, что вы пытались сделать, должно работать просто отлично, например, все эти объявления можно использовать для передачи методу foobar:

SuperClass sc1 = new SubClassSpecial1();
SubClassSpecial2 sc2 = new SubClassSpecial2();
//etc..
2 голосов
/ 02 ноября 2009

То, что вы описали, должно работать как есть.

Действительно ли obj.doSomething () вызывает реализацию суперкласса? Если это так, вы не переопределяете это должным образом. Убедитесь, что вы не изменили подпись в переопределенных версиях.

1 голос
/ 04 ноября 2009

Когда у вас есть это:

void fooBar(SuperClass obj) {
    obj.doSomething();
}

тогда время компиляции типа obj равно SuperClass. Это означает, что компилятор собирается проверить, что SuperClass имеет метод doSomething().
В время выполнения вы можете заменить подкласс SuperClass, это Принцип подстановки Лискова . Метод foobar() не знает и не должен знать, что представляет собой тип времени выполнения obj, только то, что он является производным от SuperClass, поэтому можно вызывать doSomething().

Что касается вашего примера:

fooBar( new SubClassSpecial1() );

В этом случае вам случается знать, что тип параметра runtime - SubClassSpecial1, который переопределяет doSomething(). Во всех случаях вызывается правильный метод.

Слово о рефакторинге. Вы можете рассмотреть возможность рефакторинга вашей иерархии.
Ваш базовый класс SuperClass должен определить doSomething() как абстрактный. Ваши три класса, которым требуется одна и та же реализация doSomething(), должны наследовать ее от промежуточного базового класса, который имеет эту конкретную реализацию. Ваши два специальных класса должны наследоваться непосредственно от SuperClass и иметь собственную реализацию doSomething().

...