2014-12-10 1 views
0

У меня есть интерфейс, который называется «Я»:полиморфизм и переключатель случай на основе экземпляра

package org.example; 

public interface I { 
} 

Довольно простой :-)

У меня есть классы, реализующие этот интерфейс. Они называются A, B, C, D, E и т. Д.

Классы A и B имеют определенные методы, как показано ниже. Других классов нет.

public class A implements I { 
    public void sayHelloFromA() { 
     System.out.println("Hello from A"); 
    } 
} 

public class B implements I { 
    public void sayHelloFromB() { 
     System.out.println("Hello from B"); 
    } 
} 

Мой главный метод перебирает список объектов I, и я хочу, чтобы выполнить определенные действия в зависимости от типа класса.

package org.example; 

import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    public static void main(final String[] args) { 
     final A a = new A(); 
     final B b = new B(); 
     final C c = new C(); 

     final List<I> list = new ArrayList<I>(); 
     list.add(a); 
     list.add(b); 
     list.add(c); 

     for (final I i : list) { 
      sayHello(i); 
     } 
    } 

    public static void sayHello(final A a) { 
     a.sayHelloFromA(); 
    } 

    public static void sayHello(final B b) { 
     b.sayHelloFromB(); 
    } 

    public static void sayHello(final I i) { 
     System.out.println("Unsupported"); 
    } 

} 

В чем проблема; выход:

Unsupported 
Unsupported 
Unsupported 

Я знал, что это не будет работать, но вопрос в том, как сделать эту работу без использования InstanceOf или рефлексия. Трюк заключается в том, что я не могу изменить интерфейс I (в реальной жизни, я думаю, это javax.swing.tree.TreeNode).

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

+0

Используйте экземпляр, отражение или получите имя класса и включите его. –

+0

Можете ли вы определить дополнительный 'sayHello()' метод на вашем интерфейсе? И затем, каждый из ваших классов реализует это как: класс A { sayHello() { sayHelloFromA(); } sayHelloFromA() { // Логика здесь идет }} Если вы не можете добавить метод интерфейса, вы, вероятно, могли бы расширить его – jmm

+1

Почему вы не можете определить SayHello() в интерфейсе и реализации это в каждом классе? –

ответ

3

Поскольку Java является статически типизированным языком, решая, какой метод перегрузки для вызова выполняется во время компиляции , что означает, что вы не можете вызвать перегруженный метод в соответствии с типом экземпляра, действительным, только по его , указанному.

Если вы не хотите использовать отражение, чтобы найти какой класс вашего экземпляра, но вы можете изменить А и В, можно добавить еще один интерфейс для их реализации:

public interface I2 { 
    void sayHello(); 
} 

и имеет A и B Внесите это:

public class A implements I, I2 { 
    public void sayHelloFromA() { 
     System.out.println("Hello from A"); 
    } 

    public void sayHello() { 
     sayHelloFromA(); 
    } 
} 

public class B implements I, I2 { 
    public void sayHelloFromB() { 
     System.out.println("Hello from B"); 
    } 

    public void sayHello() { 
     sayHelloFromB(); 
    } 
} 
+0

С другой стороны, я думаю, что это лучший подход, чем расширение вашего интерфейса. Это кажется более чистым, так как обязанности более четко разделены. – jmm

+0

Метод * linkage * не выполняется во время компиляции. Что происходит во время компиляции - это выбор между различными возможными перегруженными версиями метода - эта перегрузка является расширением метода * name *. У вас есть выбор имен 'sayHello (LA;)', 'sayHello (LB;)' и 'sayHello (LI;)'. Этот выбор должен быть сделан компилятором. Фактический выбор метода для выполнения происходит динамически во время выполнения. –

+0

@HotLicks - спасибо, плохой выбор слова, я исправился –