2009-04-30 27 views
0

我試圖實現事件生成器成語(http://www.javaworld.com/javaworld/jw-09-1998/jw-09-techniques.html)。儘管如此,我覺得事情在可觀察的課堂上有點「奇怪」。比方說,我有以下類:在Java中實現事件生成器成語

 
interface BakeryListener 
+ orderReceived(BakeryEvent event) 
+ orderProcessing(BakeryEvent event) 
+ orderFinished(BakeryEvent event) 
+ orderDelivered(BakeryEvent event) 

LogView, OrderReadyView etc. implements BakeryListener 
Creates a GUI for each own use 

Order 
VO/DTO object, used as the source in BakeryEvent 

BakeryDAO (the observable) 
- orders : Vector 
- listeners : Vector 
+ takeOrder, cancelOrder, bake and other regular DAO methods, 
triggering an event by calling fireEvent 
+ addBakeryListener(BakeryEvent event) 
+ removeBakeryListener(BakeryEvent event) 
- fireEvent(Order source, EVENTTYPE????) 

BakeryGUI 
Creates/gets a reference to BakeryDAO. Creates and attaches LogView, OrderReadyView as listeners on BakeryDAO. 

在我給他最初建議的鏈接「命名事件傳播方法火[偵聽器方法名。」。我覺得這是多餘的:創建一個快照並迭代每個fire-method中的偵聽器,當唯一改變的是在接口上調用哪個方法時。因此我做了一個單獨的fireEvent方法,並且它正在工作。問題是使fireEvent中的事件參數的數據類型與BakeryListeners中定義的方法保持「同步」。目前fireEvent看起來像這樣(節選):

 
for(BakeryListener listener : copyOfListeners){ 
    if(eventType.equals("received")) listener.orderReceived(event); 
    else if(eventType.equals("processing")) listener.orderProcessing(event); 
} 

...等等。我想我可以用一個枚舉,而不是一個字符串,使其無法調用fireEvent與不存在的事件類型,但我仍然必須將Type.RECEIVED映射到listener.orderReceived等?

fireEvent方法可能將BakeryListeners方法作爲參數嗎?即(僞代碼)方法聲明:

fireEvent(BakeryListeners.methods eventType, Order source) 

,然後只是直接調用適當的方法內fireEvent(無如果/切換):

call(listener, eventType(source)) 

然後,它也將是不可能建立一個事件誰沒有在界面BakeryDAO.takeOrder() - > fireEvent(eventWhoDoesntExist) - >異常中定義?

在Java中可以這樣做嗎?或者如果我瞭解錯誤的事情會更好?

回答

0

在我的這些類型的系統的實現中,我有事件(上面的BakeryEvent)攜帶有關發生了什麼的一些信息,然後讓偵聽器在接收事件時決定要做什麼(如果有的話)。這導致一個簡單inteface像

for (Listener l : registeredListeners) { 
    l.processEvent(event); 
} 

在java中不存在,這將支持你在你想被不幸調用的「默認」的方法流程圖泛型方法。

萊恩

0

在更清潔的源代碼創建每「事件」結果的一個方法,並且因此更容易閱讀。不要將太多的信息放入事件對象,而是依賴事件偵聽器接口中的方法定義。通過減少已定義方法的數量來試圖「優化」源代碼是毫無意義的。

此外,這樣你就不會遇到可能會調用未知事件的問題。

(完全不同的東西:每次觸發事件,但使用CopyOnWriteArrayList時間不克隆聽衆的名單,很會照顧的,對於你的。)

1

我覺得枚舉事件類型和包括事件中的事件類型更清晰,每種​​事件類型都有一個方法。

首先,你要避免所有的貝克聽衆不得不實施所有的方法,如果他們只對一個事件感興趣,就把它們留空。 (你有沒有實現MouseListener?)

第二,你可以添加到你以後,當你發現你需要orderBilled和orderPaied而不是添加更多的方法給所有你不需要處理這種類型的事件的偵聽器。

public class BakeryEvent { 
    public enum Type { Received, Processing,Finished,Delivered,Billed,Paied }; 

    private Type myType; 
    private Order myOrder; 

    BakeryEvent(Order order, BakeryEvent.Type bet) {//... 

    } 
    //... 
} 


public interface BakeryListener { 
    public void handleBakeryEvent(BakeryEvent be); 
} 

然後

public class OvenScheduler implements BakeryListener { 

    public void handleBakeryEvent(BakeryEvent be){ 
    if (BakeryEvent.Type.Received.equals(be.getEventType()) { 
     scheduldeOven(be.getOrder()); 
    } 
    } 
    // hey look I don't have to implement orderBilled() and then do nothing! 

}