2009-04-30 8 views
0

Ich versuche, die Event Generator Idiom (http://www.javaworld.com/javaworld/jw-09-1998/jw-09-techniques.html) zu implementieren. Ich finde die Dinge ein wenig "seltsam", wenn es um die beobachtbare Klasse geht. Lassen Sie uns sagen, dass ich die folgenden Klassen:Implementierung von Event-Generator Idiom in 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. 

In den Link habe ich anfangs empfiehlt er, „das Ereignis Verbreiter Methode Feuer Name [Hörer-method-name].“. Ich finde, dass dies redundant ist: einen Snapshot erstellen und über die Listener in jeder Fire-Methode iterieren, wenn nur die Methode geändert wird, die auf der Schnittstelle aufgerufen wird. So habe ich eine einzige FireEvent-Methode gemacht, und es funktioniert irgendwie. Das Problem besteht darin, den Datentyp des Ereignisparameters in FireEvent "synchron" mit den in BakeryListeners definierten Methoden zu halten. Derzeit ist die fireevent wie dieser (Auszug) aussieht:

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

... usw. ich denke, ich eine Enumeration anstelle einer Zeichenfolge verwenden könnte es unmöglich zu machen, fireevent mit einem eventtype zu nennen, die nicht existieren, aber Ich muss Type.RECEIVED immer noch zu listener.orderReceived usw. zuordnen?

Kann die fireEvent-Methode die BakeryListeners-Methoden als Parameter verwenden? Ie (Pseudocode) -Methode Deklaration:

fireEvent(BakeryListeners.methods eventType, Order source) 

und rufe dann nur die entsprechende Methode direkt in fireevent (ohne if/switching):

call(listener, eventType(source)) 

Dann wäre es auch unmöglich sein, ein Ereignis zu erstellen wer ist nicht in der Schnittstelle BakeryDAO.takeOrder() definiert -> fireEvent (eventWhoDoesntExist) -> Ausnahme?

Ist es möglich, dies in Java zu tun? Oder ein besserer Weg, wenn ich die Dinge falsch verstanden habe?

Antwort

0

In meiner Implementierungen dieser Arten von Systemen habe ich das Ereignis (BakeryEvent oben) tragen einige Informationen über was passiert ist und dann den Hörer entscheiden lassen, was zu tun ist (wenn überhaupt), wenn sie das Ereignis erhalten. Das führt zu einem einfachen inteface wie

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

In Java gibt es keine generischen Methoden, die Sie in einem Schema unterstützen, wo Sie ein „default“ -Methode wollen leider aufgerufen werden.

Len

0

Erstellen eine Methode pro „Ereignis“ Ergebnisse in vielen sauberen Quellcode und ist somit leichter zu lesen. Legen Sie nicht zu viele Informationen in das Ereignisobjekt, sondern verlassen Sie sich auf Methodendefinitionen in der Ereignis-Listener-Schnittstelle. Es macht keinen Sinn, Ihren Quellcode zu "optimieren", indem Sie die Anzahl der definierten Methoden reduzieren.

Auch auf diese Weise werden Sie nicht auf das Problem stoßen, dass ein unbekanntes Ereignis möglicherweise aufgerufen wird.

(etwas ganz anderes: Sie jedes Mal die Liste der Zuhörer nicht klonen Sie ein Ereignis ausgelöst, sondern eine CopyOnWriteArrayList verwenden, wird es für Sie darum kümmern.)

1

Ich denke, die Ereignistypen Aufzählen und einschließlich Der Ereignistyp im Ereignis ist sauberer als eine Methode pro Ereignistyp.

Zunächst vermeiden Sie, dass alle Baker-Listener alle Methoden implementieren müssen und lassen sie dann leer, wenn sie nur an einem Ereignis interessiert sind. (Haben Sie jemals MouseListener implementiert?)

Zweitens können Sie Enum später hinzufügen, wenn Sie herausfinden, Sie brauchen orderBilled und orderPayed mit dem Hinzufügen von mehr Methoden für alle Ihre Listener, die diese Art von Ereignis nicht verarbeiten müssen.

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); 
} 

Dann

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! 

}