2009-11-02 2 views
5

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

Таким образом, у каждого класса наследовал 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 ... 

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

+0

В этой статье следует по крайней мере указать те языки программирования, которые вы кодируете. –

+0

исправлено. добавлен тег java. Благодарю. но я думал, что это общая проблема дизайна, которая выходит за рамки языковых барьеров. – oligofren

+0

Можете ли вы дать нам рамки ваших определений классов? –

ответ

2

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

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

+0

Ну, разве это не должно быть сделано? Тип среды выполнения объявляется как класс его суперкласса, и поэтому он должен вызывать версию суперкласса. Если я принудительно ((SubClassSpecial1) obj) .doSomething(), он вызывается подклассовой версией. Или мои предположения здесь неверны о том, как работают наследования и классы времени выполнения? – oligofren

+0

Хмм ... Я написал тестовую программу, которая показывает недостатки в моих предположениях о том, как изменяются изменения в стиле Runtime объекта. Мне нужно проверить это до того, как я вернусь ... – oligofren

+2

Ваше предположение неверно. Вам не нужно бросать obj в SubClassSpecial1, чтобы получить метод SubClassSpecial1 doSomething(), это произойдет автоматически. Это полиморфизм. Попробуйте несколько тестов. –

5

Я немного смущен этой части вашего вопроса:

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

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

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

SuperClass sc1 = new SubClassSpecial1(); 
SubClassSpecial2 sc2 = new SubClassSpecial2(); 
//etc.. 
+0

ОК, я попытаюсь отредактировать эту часть и перефразировать себя. Я имел в виду, что я хотел, чтобы объект вызывал свой собственный (если переопределенный) метод, а не тот, который был из его суперкласса. И проблема в том, что, поскольку он объявлен (в объявлении метода) как экземпляр суперкласса, его тип класса времени выполнения будет иметь тип его суперкласса и, таким образом, вызовет метод суперкласса. Надеюсь, что это имеет смысл ... – oligofren

+2

Нет, вы предпочтете немного, класс, который вы используете при создании нового объекта с помощью «нового» ключевого слова, определяет тип среды выполнения вашего объекта. Поэтому в моем примере переменная sc1 SuperClass содержит ссылку на объект, тип выполнения которого является SubClassSpecial1. Я теперь это немного запутываю, надеюсь, вы получите это :-) – NickDK

+0

Спасибо, я начал подозревать, что что-то не так после ответа Терри и выяснилось, что Java не делает то, что, как я думал, будет «интуитивным» способом сделать это написав некоторый тестовый код. Все еще нахожу это поведение немного странным, но по крайней мере теперь я знаю :) – oligofren

1

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

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

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

Как ваш пример:

fooBar(new SubClassSpecial1()); 

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

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

+0

Спасибо, quamrama! Для меня это было наиболее информативным из ответов, хотя на мою главную проблему уже ответил кто-то другой. Вы заставили меня понять гораздо больше о том, как это работает, и советы по рефакторингу действительно полезны. Отличный ответ! – oligofren