2010-12-01 4 views
23

У меня есть вопрос с генераторами Java. Я надеялся, что кто-то сможет ответить. Рассмотрим следующий код:Реализация универсального интерфейса в Java

public interface Event{} 
public class AddressChanged implements Event{} 
public class AddressDiscarded implements Event{} 

public interface Handles<T extends Event>{ 
    public void handle(T event); 
} 

Я хочу осуществить это Рукоятки интерфейс, как это:

public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{ 
    public void handle(AddressChanged e){} 
    public void handle(AddressDiscarded e){} 
} 

Но Java не позволит реализовать Рукоятки дважды с помощью Generic. Я смог выполнить это с помощью C#, но не могу определить обходное решение в java без использования Reflection или instanceof и casting.

Есть ли способ в Java реализовать интерфейс Handles, используя оба общих интерфейса? Или, возможно, еще один способ написать интерфейс Handles, чтобы конечный результат мог быть достигнут?

ответ

9

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

public class AddressHandler implements Handles<Event>{ 
    public void handle(Event e){ 
     if(e instanceof AddressDiscarded){ 
     handleDiscarded(e); 
     } else if(e instanceof AddressChanged){ 
     handleChanged(e); 
     } 
    } 
    public void handleDiscarded(AddressDiscarded e){} 
    public void handleChanged(AddressChanged e){} 
} 
+4

Это спорно ... Это "InstanceOf каскад" является очень процедурной paragidm. Конечно, это работает, но ИМХО это не очень хороший стиль. Но, следовательно, наличие разных имен методов также может быть не идеальным, это, вероятно, вопрос вкуса. – 2010-12-01 15:43:17

+1

Это то, что я сделал бы. Вам не обязательно :) – 2010-12-01 15:44:41

+0

-1: Вы можете реализовать несколько интерфейсов в Java. – 2010-12-01 15:45:40

1

AFAIK вы не можете сделать это, потому что при компиляции исходного кода в Java они оба сводятся к handle(Event), что делает метод неоднозначен.

Общая информация недоступна во время выполнения на Java, в отличие от C#. Вот почему он работает, как вы описываете.

Вам нужно будет изменить имена методов, чтобы сделать их уникальными, например handleAddressChanged и handleAddressDiscarded.

Это действительно одна из слабых сторон генераторов Java.

2

Нет, потому что разные «конкретные» общие типы в Java компилируются до того же типа. Реальный интерфейс вашего объекта будет осуществлять это:

public interface Handles { 
    public void handle(Event event); 
} 

И, очевидно, вы не можете иметь два различных метода с одинаковой сигнатурой ...

17

Going после @Amir Raminfar, вы можете использовать шаблон visitor

interface Event{ 
void accept(Visitor v); 
} 
interface Visitor { 
void visitAddressChanged(AddressChanged a); 
void visitAddressDiscarded(AddressDiscarded a); 
} 

class AddressChanged implements Event{ 
@Override 
public void accept(Visitor v) { 
    v.visitAddressChanged(this); 
} 
} 

class AddressDiscarded implements Event{ 
@Override 
public void accept(Visitor v) { 
    v.visitAddressDiscarded(this); 
} 
} 

class AddressHandler implements Visitor { 
    void handle(Event e){ 
     e.accept(this); 
    } 
    public void visitAddressChanged(AddressChanged e){} 
    public void visitAddressDiscarded(AddressDiscarded e){} 
} 
0

К сожалению, нет. Обычным решением (жирным, уродливым, быстрым) является создание одного интерфейса Handles (то есть HandlesAddressChange, HandlesAddressDiscarded) и придать каждому из них другой метод (handleAddressChange(...), handleAddressDiscarded()).

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

Или вы можете использовать анонимные классы.

0

Это недопустимо, потому что Java стирает общие подписи во время компиляции. Метод интерфейса фактически будет иметь подпись

public void handle(Object event); 

У вас есть два варианта.Либо реализовать отдельные обработчики для различных событий:

public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ } 
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ } 

или реализуют один обработчик для всех, но проверить тип входящего события:

public void handle(Event e){ 
    if (e instanceof AddressChanged) { 
    handleAdressChanged(e); 
    } 
    else if (e instanceof AddressDiscareded) { 
    handleAdressDiscarded(e); 
    } 
} 
0

Реализация, как это не будет работать из-за ограничений, спецификация java. Но если вы не боитесь использовать АОП или своего рода IOC-Container, вы можете использовать для этого аннотации. Чем ваши аспекты или контейнер могут управлять инфраструктурой обмена сообщениями и вызывать методы, которые вы комментируете.

Сначала вы должны создать аннотации.

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface EventConsumer {} 

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Handles{} 

вы можете аннотировать ваш класс так:

@EventConsumer 
public class AddressHandler{ 
    @Handles 
    public void handle(AddressChanged e){} 
    @Handles 
    public void handle(AddressDiscarded e){} 
} 
Смежные вопросы