Service Locator je obecný návrhový vzor, který dodává jeho uživatelům instance požadovaných služeb. Existuje několik variant implementace tohoto vzoru a dokonce jsou od něj odvozeny i další specifcké vzory.
Singleton
Nejjednodušší implementaci service locatoru zná asi každý, kdo kdy
s návrhovými vzory koketoval – je jím starý známý Singleton! Krom
toho, že Singleton svou vnitřní implementací zajišťuje garantovaný
lifetime instance, tak tuto instanci i poskytuje – typicky pomocí statické
vlastnosti Instance v horších jazycích pak funkcí
getInstance().
Abstract Factory
Další z častých implementací service locatoru je Factory, jde
o další konkrétnější odvozeninu vzoru, která má semantiku nejen
instance dodávat, ale i vytvářet. V důslednějších variantách má
factory na starosti i řádnou destrukci vytvořeného objektu. Já to
nazývám „šrotovným“. :) Factory většinou vytváří nové instance
pomocí metody Create() nebo nějaké její variace.
Generický Service Locator
Další častou implementací je obecný service locator v mnoha
aplikacích/frameworcích taky přezdívaný jako Registry nebo
Kernel a podobně. Základním rozhraním většiny IoC kontejnerů
je právě takovýto service locator. Většinou instance dostaneme zavoláním
metody GetInstance() nebo Resolve().
Jak vidíte, vzory jsou to známé, celkem běžně užívané, narážíme na ně denně. Tak co je špatně? Proč někdo používá označení Service Locator pejorativně?
Usage pattern
Service locator totiž není jen návrhovým vzorem, ale i vzorem užití. A tady narazíme na jádro pudla. Vezměme si mou oblíbenou ukázku se Singletonem. Tento vzor jal se býti častován anti-patternem. Je to snad, kvůli tomu, že by to byl špatný návrhový vzor? Myslím, že ne. Tento vzor se spojil v lidských hlavách se vzorem užití, který je špatný!
Ruku na srdce, kolikrát ve svém kódu voláte, třeba
HttpContext.Current místo toho, abyste si ho nechali injektovat
konstruktorem?
public class SomeWebFoo {
public void DoWork() {
// code
if (HttpContext.Current.IsDebuggingEnabled) {
// code
}
}
public class BetterWebFoo {
readonly HttpContextBase httpContext;
public BetterWebFoo(HttpContextBase httpContext) {
this.httpContext = httpContext;
}
public void DoWork() {
// code
if (httpContext.IsDebuggingEnabled) {
// code
}
}
První třída používá Service Locator usage pattern, druhá inversion of control. V prvním případě skrytě přistupujeme přes statickou vlastnost (globální proměnná) k instanci konkrétního typu. Druhá třída svou závislost veřejně deklaruje, ale je jí navíc jedno, jaký konkrétní typ dostane – závisí pouze na abstrakci. Proč je první třída ve většině případů horší nechám už na vás. Určitě na to přijdete. ;)










