Перегрузка методов с использованием производных типов в качестве параметров в Java - PullRequest
3 голосов
/ 25 июля 2011

Допустим, у меня есть существующий код, который я хочу расширить, но также и избегать его максимально возможного изменения.

Где-то вокруг этого кода есть метод, который получает некоторый тип.

Engine.method(Base b) 

Теперь я хочу расширить эту функциональность. Поэтому я расширяю Base до типа с именем Derived, который содержит еще несколько необходимых мне данных, и я также реализую другой метод, который получает тип Derived и делает с ним что-то другое.

Engine.method(Derived d)

Но я не хочу менять исходный вызов на «метод». Мне каким-то образом удалось создать экземпляр правильного типа (Base или Derived) с помощью флага, но, поскольку исходный вызов принимает Base, мой новый метод вызываться не будет.

Base b = null;
if(flag) {
   b = new Derived()
} else{
   b = new Base()
} 
Engine.method(b) 

Проблема в том, что теперь мой Engine.method (Derived d) больше не будет вызываться. Я обошел его, используя кастинг

if(flag)
Engine.method((Derived)b) 

Но это неправильно и глупо. Есть предложения?

Я всегда могу сделать:

if(flag) {
   Engine.methodForBase(new Base())
} else{
   Engine.methodForDerived(new Derived())
} 

Но можете ли вы придумать что-нибудь лучше?

Спасибо

Ответы [ 3 ]

4 голосов
/ 25 июля 2011

Это происходит потому, что Java использует одну отправку. Это означает, что в вашем случае вызываемый метод зависит от типа ссылки "b", то есть Base, а не от типа экземпляра, который содержит "b". Поэтому метод xpto. (Base b) всегда будет вызываться.

Вы действительно должны разыграть его или использовать последний подход, который вы написали.

3 голосов
/ 25 июля 2011

Напишите это:

class Engine {
    public static void method(Base argument) {
        if (argument instanceof Derived) {
            // ...
        }
        else {
            // ...
        }
    }
}

Но, вероятно, вы должны расширить класс Engine, чтобы учесть больше полиморфизма, например, сделать что-то вроде этого:

interface Engine<T extends Base> {
    void method(T argument);
}

И иметь реализациидля Base и Derived вот так:

class BaseEngine implements Engine<Base> {
    @Override
    public void method(Base argument) { ... }
}

class DerivedEngine implements Engine<Derived> {
    @Override
    public void method(Derived argument) { ... }
}
0 голосов
/ 25 июля 2011

Почему бы просто не вызвать метод с параметром правильного типа?

Base b = null;
if (flag) {
    Derived d = new Derived()
    Engine.method(d); // so the correct method will be used for Derived
    b = d;
} else{
    b = new Base()
    Engine.method(b) 
}

Вы также можете рассмотреть возможность повторного использования method(Base b):

public void method(Derived d) {
    method((Base)b);
    ...
}
...