2009-08-19 15 views
26

Załóżmy, że mam klasę Małpa, która czasami musi nabyć instancję Banana. Sposób dostarczania tego banana nie jest interesujący dla małpy, ale inicjuje pozyskiwanie banana.Wydarzenie, przekazanie lub interfejs?

Teraz mam co najmniej trzy możliwe sposoby podłączenia mojej małpy do dostawcy bananów. Jaki jest najlepszy sposób na zrobienie tego?

1. Zdarzenie

Podnieść zdarzenia Monkey.BananaNeeded. Procedura obsługi zdarzeń ustawia właściwość BananaNeededEventArgs.Banana.

2. Interfejs

Invoke IBananaProvider.GetBanana. Instancja IBananaProvider jest wstrzykiwana małpie jako argument konstruktora lub przez właściwość.

3. Delegat

Wywołuje delegata typu System.Func<Banana>. Delegat jest wstrzykiwany małpie jako argument konstruktora lub poprzez właściwość. Ten jest kuszący, ponieważ nie wymaga deklaracji żadnych dodatkowych interfejsów lub klas, ale najwyraźniej nie jest popularnym wyborem.

+3

+1 za zabawne przykłady i przyzwoite pytanie, ale oczywiście małpa nie dba o to, że kupuje banana, wszystko, o co troszczy się, to żarcie na smakowitą ucztę. –

+2

Fat monkey: while (true) _provider.GetBanana.Eat(); – Guffa

+6

Nie zapomnij wyrzucić skórek bananów. Nie chcemy przecieku skóry na ręce. –

Odpowiedz

6

Nie podoba mi się wydarzenie i opcje delegowania, chyba że istnieje mechanizm, który zapewni, że wiele programów obsługi nie zostanie dołączonych. Dlatego opcja 2 jest zwycięzcą, IMO.

+0

Nie możesz dołączyć więcej niż jednej metody do delegata ... – Guffa

+4

@Guffa - Eh? Wszyscy delegaci w .NET to MulticastDelegate, a cała uwaga polega na tym, że * możesz * dołączać do niej wiele metod. Jak sądzisz, jak działają wydarzenia? –

+0

Tak, możesz łączyć delegatów, ale w tym przypadku jest to całkowicie bezużyteczne, ponieważ tylko ostatni może zwrócić banan. – Guffa

1

Najlepszym sposobem w powyższym scenariuszu jest przejście do interfejsu. W terminach OOAD możemy zdefiniować powyższy scenariusz, ponieważ klasa Monkey ma banan.

1

Zwykle używam 2.

IBananaProvider bananaProvider = ProviderFactory.Get<IBananaProvider>(); 
+0

+1 ... ale czy małpa nie musi wiedzieć, jak dostać się do fabryki po banan? –

+0

@Justin Niessner: na pewno, możesz mieć fabrykę Providerfactory na podstawie pliku konfiguracyjnego. – Gregoire

4

modelu zdarzeń działa najlepiej, jeśli istnieje kilka możliwych dostawców bananów, czyli małpa prosi wszystkich dostawców z kolei za banana, a pierwszy, który może dostarczyć jedną dostarczy to.

Pozostałe dwa modele działają dobrze na jedno bananowe przysłowie dla małpy. Delegat łatwiej jest utworzyć dostawcę, a interfejs jest bardziej uporządkowany.

1

Są operacje na Monkey, które sprawiają, że wymaga Banana.

Potrzeba małpy, aby uzyskać banan, to du tych operacji. Z pewnością możesz przekazać banan jako parametr operacji.

Usuwam zależność pieniędzy od dostawcy IBananaProvider.

class Monkey 
{ 
    void FeedWith(Banana banana) { ... } 
} 

Będzie to odpowiedzialność osoby dzwoniącej za zdobycie banana, a nie Małpy.

Polecam tutaj nie do wstrzykiwania usług w podmiotach.

+1

Małpa może potrzebować nowego banana, kiedy skończy pierwszy. :-) – djna

+0

W takim przypadku podaj IBananaProvider jako argument, Małpa może zdecydować, ile bananów chce. – thinkbeforecoding

+0

Ale znowu Martin Fowler uważa Anemiczny Model Małpy za anty-wzór: http://martinfowler.com/bliki/AnemicDomainModel.html –

1

Idealnie wtrysk zależności jest bardziej ogólnie akceptowanym podejściem.

Kolejne podejście do próby to kolejki wiadomości .

W tym scenariuszu Monkey może zasadniczo "opublikować" wiadomość do niektórych kolejki na pyszne banana. Ten "posting" wyzwalałby jakiegoś dostawcę usługi, który monitoruje kolejkę, aby następnie spełnić żądanie - którego faktyczna instancja dostawcy odpowiada, jest nieistotna. Monkey będzie czekać na odpowiedź na oryginalną wiadomość i podejmie działanie, gdy nadejdzie przesyłka z numerem BananaProvider.

Kolejki wiadomości oddzielają dostawców i konsumentów. To prawda, że ​​nadal istnieje pewna forma umowy ", ale , który znajduje się na drugim końcu żądania i odpowiedzi, nie ma znaczenia:

1

Zgodzę się i powiem, że opcja 2 jest najlepszym rozwiązaniem. Zazwyczaj ma to na celu, cóż delegować coś, innymi słowy coś robić, a wydarzenia mają na celu natychmiastową reakcję na coś, co się wydarzyło, zwykle związane z użytkownikiem. Interfejs po prostu mówi: "To jest tutaj i możesz to zrobić". Nie chcę, żeby banan lub małpa robili cokolwiek na początku i nie chcesz, aby użytkownik bezpośrednio wchodził w interakcję z wewnętrznym działaniem twojego kodu, interfejs wygrywa, potrzebujesz tylko wiedzieć, że małpa może odbierać banany. To, co zdecyduje się zrobić z tymi bananami, zależy od niego, a sam banan, jak również otaczający go kod nie powinny zajmować się to.

Powiązane problemy