2008-10-29 19 views
15

Powiedzmy, że mam klasę o nazwie PermissionManager, która powinna istnieć tylko raz dla mojego systemu i zasadniczo spełnia funkcję zarządzania różnymi uprawnieniami dla różnych akcji w mojej aplikacji. Teraz mam pewne klasy w mojej aplikacji, które muszą być w stanie sprawdzić pewne uprawnienia w jednej z jego metod. Ten konstruktor klasy jest obecnie publiczny, tzn. Używany przez użytkowników API.Practical Singleton & Dependency Injection question

Aż kilka tygodni temu, chciałbym mieć po prostu miał moja klasa wywołać następujące pseudo-kod gdzieś:

 PermissionManager.getInstance().isReadPermissionEnabled(this) 

Ale odkąd zauważyli wszyscy tutaj nienawidząc singletons + ten rodzaj sprzęgła, byłem zastanawiając się, jakie byłoby lepsze rozwiązanie, ponieważ argumenty, które czytałem przeciwko singletonom, wydają się mieć sens (nie do sprawdzenia, wysokie sprzężenie itp.).

Czy rzeczywiście powinienem wymagać od użytkowników interfejsu API przekazania instancji PermissionManager w konstruktorze klasy? Mimo że chcę, aby dla mojej aplikacji istniała tylko jedna instancja PermissionManager?

Czy mam zamiar o tym wszystkim źle i powinien mieć niepubliczne konstruktora i fabryka gdzieś, które przechodzi w instancji PermissionManager dla mnie?


Dodatkowe informacje Zauważ, że kiedy mówię „Dependency Injection”, mówię o DI Pattern ... Nie używam żadnych ram DI jak Guice lub wiosną. (... jeszcze)

Odpowiedz

3

Jeśli korzystasz ze schematu wtrysku zależności, wówczas najpowszechniejszym sposobem na obsłużenie tego jest przekazanie obiektu klasy PermissionsManager w konstruktorze lub posiadanie właściwości typu PermissionsManager, którą struktura ustawi dla ciebie.

Jeśli nie jest to wykonalne, dobrym wyborem jest posiadanie przez użytkowników instancji tej klasy przez fabrykę. W takim przypadku fabryka przekazuje właściwość PermissionManager do konstruktora, gdy tworzy klasę. W uruchomieniu aplikacji należy najpierw utworzyć pojedynczy PermissionManager, a następnie utworzyć fabrykę, przekazując w Menedżerze uprawnień PermissionManager.

Masz rację, że zwykle jest nieporęczne dla klientów klasy, aby wiedzieć, gdzie znaleźć prawidłową instancję PermissionManager i przekazać ją (lub nawet dbać o to, że twoja klasa używa PermissionManager).

Jednym z rozwiązań kompromisowych, jakie widziałem, jest nadanie klasie właściwości PermissionManager. Jeśli właściwość została ustawiona (powiedzmy w teście jednostkowym), użyjesz tej instancji, w przeciwnym razie użyjesz singletonu. Coś jak:

PermissionManager mManager = null; 
public PermissionManager Permissions 
{ 
    if (mManager == null) 
    { 
    return mManager; 
    } 
    return PermissionManager.getInstance(); 
} 

oczywiście, ściśle rzecz biorąc, PermissionManager powinny wdrożyć jakiś interfejs IPermissionManager i to co się inna klasa powinna odwoływać się więc obojętne realizacja może być podstawiona łatwiej podczas testów.

+1

Punkt dotyczący wstrzykiwania za pośrednictwem interfejsu jest bardzo ważny. Możliwość wyśmiewania obiektu PermissionManager w testach sprawia, że ​​DI jest potężnym podejściem do testowania kodu. –

+1

co jeśli menedżer PermissionManager ma zależność. Czy istnieje mniej dziwny sposób niż PermissionManager.getInstance (Foo)? ? –

0

Wzór singletonowy sam w sobie nie jest zły, co sprawia, że ​​jest brzydki w sposobie, w jaki jest powszechnie używany, jako wymaganie tylko jednego wystąpienia danej klasy, co moim zdaniem jest duży błąd.

W tym przypadku ustawiam PermissionManager na statyczną klasę, chyba że z jakiegoś powodu potrzebujesz jej jako typu instancyjnego.

2

Można rzeczywiście rozpocząć od wstrzyknięcia Menedżera uprawnień. To sprawi, że Twoja klasa będzie bardziej sprawdzalna.

Jeśli powoduje to problemy dla użytkowników tej klasy, możesz poprosić o użycie metody fabrycznej lub fabryki abstrakcyjnej. Można też dodać konstruktor bez parametrów, który dla nich wywoła, który wstrzykuje PermissionManager, podczas gdy testy używają innego konstruktora, którego można użyć do wyśmiewania PermissionManager.

Rozdzielenie zajęć bardziej zwiększa elastyczność zajęć, ale może także utrudnić korzystanie z nich. To zależy od sytuacji, której potrzebujesz. Jeśli masz tylko jednego PermissionManager i nie masz problemu z testowaniem klas, które go używają, nie ma powodu, aby używać DI. Jeśli chcesz, aby ludzie mogli dodawać własne implementacje PermissionManager, DI jest drogą do zrobienia.

2

Jeśli subskrybujesz metodę wykonywania zastrzyków zależnych od zależności, niezależnie od tego, jakie klasy będą potrzebować, Twój PermissionManager powinien zostać wstrzyknięty jako instancja obiektu. Mechanizm, który kontroluje jego instancję (w celu wyegzekwowania pojedynczej natury) działa na wyższym poziomie. Jeśli korzystasz z frameworka zależnego od zależności, takiego jak Guice, może on wykonać działania wymuszające. Jeśli wykonujesz okablowanie obiektowe ręcznie, zastrzyk zależności preferuje grupowanie kodu, który wykonuje instancję (nowy operator pracy) z dala od logiki biznesowej.

Tak czy inaczej, klasyczny "kapitał-S" Singleton jest ogólnie postrzegany jako anty-wzór w kontekście zastrzyku zależności.

Stanowiska te były wnikliwe dla mnie w przeszłości:

1

Należy więc rzeczywiście wymagają użytkownicy API przekazać w instancji PermissionManager w konstruktorze klasy? Mimo że chcę, aby dla mojej aplikacji istniała tylko jedna instancja PermissionManager?

Tak, to wszystko, co musisz zrobić. To, czy zależność jest pojedyncza/na żądanie/na wątek, czy metoda fabryczna, jest odpowiedzialne za twój kontener i konfigurację. W świecie .net najlepiej byłoby mieć zależność od interfejsu IPermissionsManager w celu dalszego zredukowania sprzężenia, zakładam, że jest to najlepsza praktyka w Javie.

Powiązane problemy