2009-04-30 6 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

이러한 종류의 시스템을 구현할 때 어떤 이벤트가 발생했는지에 대한 정보를 가지고 있으며, 이벤트를 수신 할 때 청취자가 무엇을해야할지 결정하도록합니다. 즉 간단한 inteface을 리드 같은

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

자바에서 당신이 "기본"방법은 불행히도 호출하려는 계획에서 당신을 지원하는 더 일반적인 방법이 없습니다.

0

많은 청소기 소스 코드에서 "이벤트"결과 당 하나의 방법을 만들기 때문에 쉽게 읽을 수 있습니다. 이벤트 개체에 너무 많은 정보를 넣지 말고 대신 이벤트 수신기 인터페이스의 메서드 정의를 사용하십시오. 정의 된 메소드의 수를 줄임으로써 소스 코드를 "최적화"하려고하는 것은 의미가 없습니다.

또한이 방법을 사용하면 알 수없는 이벤트가 호출 될 수있는 문제가 발생하지 않습니다.

(완전히 다른 뭔가 :., 그것은 당신을 위해 처리됩니다 청취자의리스트 당신이 이벤트를 발생하지만 CopyOnWriteArrayList를 사용할 때마다 복제하지 않음)

1

을 나는 이벤트 유형을 열거 등 생각 이벤트의 이벤트 유형은 이벤트 유형별로 하나의 메소드보다 깔끔합니다.

먼저 모든 베이커 리스너가 모든 메소드를 구현하지 않아도되고 하나의 이벤트에만 관심이있는 경우 비워 두는 것을 피하십시오. (MouseListener를 구현 한 적이 있습니까?)

둘째, 나중에 해당 유형의 이벤트를 처리 할 필요가없는 모든 리스너에 메소드를 추가하여 orderBilled 및 orderPanied가 필요한 경우 Enum을 추가 할 수 있습니다. 그런 다음

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! 

}