5

Zdaję sobie sprawę, że ten temat został zabity na śmierć, ale wciąż walczę i mogę zrobić z jakąś konkretną pomocą.Luźno sprzężony wzór obserwatora

Moim celem jest zaimplementowanie prostego wzorca obserwatora między jakimś obserwowalnym (powiedzmy psem) a jakimś słuchaczem (powiedzmy Właściciel).

Ostatecznie właścicielem będzie "widok", a pies "modelem" w paradygmacie MVC. Używam Psa i Właściciela tylko po to, aby uprościć rzeczy tutaj.

Próbowałem użyć wbudowanych w Java klas Obserwator/Obserwowalny, ale zdałem sobie sprawę, jak źle metoda aktualizacji Obserwatorów() jest - otrzymuje POJO i musiałbym sprawdzić/odrzucić to POJO w metodzie update(). Bardzo chciałbym, aby moja metoda "update()" otrzymywała coś, czego można się spodziewać.

Więc po kilka samouczków, w tym ten jeden, który wykorzystuje Dog/właściciel jako przykład:

http://www.youtube.com/watch?v=qw0zZAte66A

Tu zostały pokazane jak toczyć własne Observer/odnotowano klas. W pseudo kod, co mam teraz jest to:

Dog/Model { 

    List listeners; 

    public fireDogHungryEvent() { 

     foreach listener { 
      listener.onDogHungry(this); 
     } 
    } 

    public fireDogPeeEvent() { 

     foreach listener { 
      listener.onDogNeedsToPee(this); 
     } 
    } 

    public getHungerLevel() { return hungerLevel; } 
    public getBladderCapacity() { return bladderCapacity; } 
} 

Owner/View { 

    public onDogHungry(model) { 
     println(model.getHungerLevel()); 
    } 

    public onDogNeedsToPee(model) { 
     println(model.getBladderCapacity()); 
    } 
} 

Więc teraz zamiast jednego metoda update(), mam metody, które zajmują szczególne wydarzenia. Znakomity. Obecnie jestem zadowolony z klasy Właściciel/widok. Wie o metodach Dog/Model i to jest w porządku (myślę).

Nie podoba mi się to, że pies/model ma odniesienia do metod w widoku Właściciel/widok. Czytałem niezliczoną ilość razy i całkowicie zgadzam się, że model nie powinien być ściśle powiązany z jego poglądami, tak jak wydaje się być powyżej. Nie jestem również zainteresowany wszystkimi metodami "ognia" u psa/modela, robiąc prawie to samo; zapętlając wszystkich słuchaczy i po prostu wywołując inną metodę na każdym słuchniku.

Czy możliwe jest dalsze rozłączenie tych zależności i czy nie są dostępne specjalne metody dla psów/modeli? Jeśli tak, jaki jest najlepszy sposób uzyskania danych Dog/Modelu do właściciela/widoku i poprawnej pracy z nim?

Dzięki

+0

Jakie metody "psa" mają odniesienia do widoku? Nie widzę żadnych. – SJuan76

+0

Najlepszym sposobem jest użycie interfejsu, który sugeruje samouczek wideo. Czy słuchacz jest interfejsem w twojej implementacji? –

+0

SJuan76 - referencje, o których mówię, to połączenia do listener.onDogHungry i listener.onDogNeedsToPee w metodach "ognia" psa. – whoshotdk

Odpowiedz

3

Należy interface dala znajomości konkretnej implementacji zarówno z Observer i Observable

public enum EventType { 

    HUNGRY, 
    PEE; 
} 

public interface DogEvent { 

    EventType getType(); 
} 

public interface DogListener { 

    void fireEvent(DogEvent event); 
} 

public class Dog { 

    private final Set<DogListener> listeners = new CopyOnWriteArraySet<DogListener>(); 

    public void register(final DogListener dogListener) { 
     listeners.add(dogListener); 
    } 

    public void unregister(final DogListener dogListener) { 
     listeners.remove(dogListener); 
    } 

    public void firePeeEvent() { 
     fireEvent(new DogEvent() { 
      @Override 
      public EventType getType() { 
       return EventType.PEE; 
      } 
     }); 
    } 

    public void fireHungryEvent() { 
     fireEvent(new DogEvent() { 
      @Override 
      public EventType getType() { 
       return EventType.HUNGRY; 
      } 
     }); 
    } 

    private void fireEvent(final DogEvent dogEvent) { 
     for (final DogListener listener : listeners) { 
      listener.fireEvent(dogEvent); 
     } 
    } 
} 

public class Owner implements DogListener { 

    @Override 
    public void fireEvent(DogEvent event) { 
     switch (event.getType()) { 
      case PEE: 
       System.out.println("Someone take the dog out"); 
       break; 
      case HUNGRY: 
       System.out.println("I can't believe the dog is hungry _again_!"); 
       break; 
     } 
    } 
} 

W tym przypadku Dog nie wie o realizacji Owner po prostu wiadomo, że Owner jest DogListener.

Z drugiej strony Owner nie wie o Dog po prostu wie, że ma przychodzące DogEvent.

+0

Podoba mi się ta odpowiedź ze względu na jej klarowność, dziękuję Borysu. Nie * szczególnie * podoba mi się opis przypadku, który musi sprawdzić, jakie wydarzenie miało miejsce, ale myślę, że nie dzieje się to po prostu przez magię: D Prześlę to z kilkoma obserwatorami/słuchaczami i zobaczę, jak sobie poradzę. Przyjmuję tę odpowiedź w pewnym momencie dzisiaj, jeśli uda mi się z tym przekonać coś sensownego! – whoshotdk

+0

Ah Właśnie zdałem sobie sprawę, że jest to znacznie lepsza realizacja tego, co próbowałem wcześniej w moich próbach; z wyjątkiem użycia refleksji do wywołania metod opartych na nazwie ciągu zamiast obiektu zdarzenia. Myślę, że to zadziała: D – whoshotdk

+0

"Wyliczenie" było tylko sugestią - można użyć wzorca gościa, aby w pełni wykorzystać polimorfizm. –

1

Dla celów MVC (szczególnie dla MVP) Mam zebrane dobre doświadczenia z programowaniem baz konferencyjnej. Więc potrzebujesz EventBus, który będzie używany przez psa i właściciela. Właściciel zasubskrybuje określone zajęcia, takie jak HungerLevelIncrease, a pies wystrzeli takie zdarzenia. Dla przykładu twojego właściciela psa byłoby to trochę dziwne, ponieważ właściciel nie znał swoich psów, ale programowanie GUI jest miłym i łatwym rozwiązaniem do rozłączenia rzeczy szczególnie między innymi kontrolerami.

Można łatwo utworzyć magistralę samodzielnie lub skorzystać z tej z google guava.

Jest to najlepszy sposób, jaki znam, aby stworzyć naprawdę luźne połączenie.

+0

To początkowo wydawało mi się dobrym pomysłem, ale po krótkim lekturze inni zauważyli, że ten wzór zasadniczo sprawia, że ​​każdy obserwator/słuchacz musi wiedzieć o jednym autobusie. Dodanie nowych typów zdarzeń oznaczałoby również zmianę tego autobusu. Zobacz: http://stackoverflow.com/questions/3987391/why-people-use-message-event-buses-in-theircode. Może to nie jest tak źle, jak się wydaje, idk. – whoshotdk

+1

@ user2373021 spojrzałeś na coś takiego jak [mbassador] (https://github.com/bennidi/mbassador) - to jest adnotacja, więc wszystko, czego potrzebujesz, to nanoszenie komentarzy na swoich słuchaczy i wywnioskuje, czego chcą słuchać parametry metody. Może również wysyłać wiadomości asynchronicznie ... –

+0

@ user2373021 to prawda, że ​​musisz dodać autobus do wszystkich klas, które go potrzebują. Jednak większość czasu dodasz pojemnik do wstrzyknięć zależnych do większych aplikacji, które mogą wstrzyknąć Ci eventBus. Jednak dodanie nowych typów wydarzeń nie powinno mieć żadnego wpływu na Twój autobus. Jeśli masz tylko kilka klas, wybrałbym również proste rozwiązanie dla osób słuchających, ale jeśli masz więcej dialogów i wiele dialogów rozmawiasz ze sobą iz innymi klasami (np. Serwer). Chciałbym spróbować wypróbować mechanizm EventBus. – mszalbach