2011-01-19 14 views
7

在下面,我希望EventHandler以其他方式處理EventA,以另一種方式處理EventB,以及其他任何事件(EventC,EventD)。 EventReceiver僅接收對事件的引用並調用EventHandler.handle()。總是被調用的版本當然是EventHandler.handle(Event event)。以Java多態調度

沒有使用instanceOf,有沒有一種方法來多態調度(也許通過EventHandler或泛型中的另一種方法)到適當的句柄方法?

class EventA extends Event { 
} 

class EventB extends Event { 
} 

class EventC extends Event { 
} 

class EventD extends Event { 
} 

class EventHandler { 
    void handle(EventA event) { 
     System.out.println("Handling EventA"); 
    } 

    void handle(EventB event) { 
     System.out.println("Handling EventB"); 
    } 

    void handle(Event event) { 
     System.out.println("Handling Event"); 
    } 
} 

class EventReceiver { 
    private EventHandler handler; 

    void receive(Event event) { 
     handler.handle(event); 
    } 
}  

回答

10

聽起來像應用(變體)Visitor pattern的情況。 (在主流面向對象的語言,如C++,C#和Java中,方法是單個調度,即,僅可以在一種類型的多態型在一個時間。訪客允許一個實施雙調度。)

然而,這需要您還可以修改Event類,並創建從Event到(EventHandler的基本接口)的依賴關係。

class EventA extends Event { 
    public handleBy(EventHandler eh) { 
    eh.handleEventA(this); 
    } 
} 

class EventB extends Event { 
    public handleBy(EventHandler eh) { 
    eh.handleEventB(this); 
    } 
} 

class EventHandler { 
    void handleEventA(EventA event) { 
     System.out.println("Handling EventA"); 
    } 

    void handleEventB(EventB event) { 
     System.out.println("Handling EventB"); 
    } 

    void handle(Event event) { 
     event.handleBy(this); 
    } 
} 
+1

+1對訪問者模式 – 2011-01-19 16:00:44

+0

我想過Visitor模式和非循環Vistor模式。不幸的是,我無法修改Event類。而且,我需要隨着時間的推移添加許多專門的活動。 – user581638 2011-01-19 17:08:31

0

您可以使用地圖和地圖事件類型來處理事件。

Map<Class<? extends Event>, Handler> map = 
    new HashMap<Class<? extends Event>, Handler>(); 

void receive(Event event) { 
    Handler handler = map.get(event.getClass()); 
    handler.handle(event); 
} 
1

這是一個用例double-dispatch,沒有(這作爲一個可能確實知道的是無論是所謂的觀衆)?我將僅實現EventA的示例

class Event { 
    /** 
    * Will do some type escalation 
    */ 
    void handleWith(EventHandler care) { 
     care.handle(this); 
    } 
} 



class EventA extends Event { 
    /** 
    * As event is EventA, this implementation is called, with its correct type forced by the cast 
    */ 
    void handleWith(EventHandler care) { 
     care.handle((EventA) this); 
    } 
} 

class EventHandler { 
    /** 
    * Finally comes here 
    */ 
    void handle(EventA event) { 
     System.out.println("Handling EventA"); 
    } 

    void handle(EventB event) { 
     System.out.println("Handling EventB"); 
    } 

    void handle(Event event) { 
     System.out.println("Handling Event"); 
    } 

    /** 
    * Go here first and dispatch call to Event class 
    */ 
    void doHandle(Event event) { 
     event.handleWith(this); 
    } 
} 

class EventReceiver { 
    private EventHandler handler; 

    void receive(Event event) { 
     handler.doHandle(event); 
    } 
}  
1

Java只在對象上調用方法時具有多態調度。這意味着,獲得真正的多態性的唯一方法是將handle()方法放入Event接口本身。我實際上會說這是整體更好,更OO的解決方案,因爲對數據對象進行操作的「處理程序」是相當程序化的。

任何其他解決方案(例如鍵入該類的處理程序對象的映射)將變得更加複雜和不靈活,尤其是有關繼承的問題。

0

我知道如何通過一些預處理來做到這一點。使用這樣的事情:

public abstract class EventHandler<T extends Event> { 
    public abstract void handle(T event, Class<T> c); 
    public abstract Class<T> handles(); 
} 

public class EventHandlerA extends EventHandler<EventA> { 
    @Override 
    public void handle(EventA event, Class<EventA> c) { 
     System.out.println(event); 
    } 

    @Override 
    public Class<EventA> handles() { 
     return EventA.class; 
    }  
} 

然後用地圖來組織你的處理程序

HashMap<Class<?>,Collection<EventHandler<?>> handlers; 

當一個事件需要處理的只是檢索地圖的處理程序。如果Class.equals()和Class.hashCode()不能工作,那麼你需要一個包裝來獲得你想要的行爲。