Service Locator Nedir ve Anti-Pattern mı?

SOLID prensiplerini örnek kodlar ile anlattığım videolarımı izlemek için YouTube kanalımda ki SOLID Prensipleri listemi ziyaret edebilirsiniz. YouTube Kanalıma abone olarak, her hafta eklenen yazılımcılar için programlama ve kariyer video eğitimlerime ulaşabilirsiniz.

Dün akşam SOLID prensipler üzerine bir konuşmaya katıldım. Yazılıma yeni başlayanlar yada daha çok procedural programlama dillerinden gelenler için anlaşılır bir anlatım oldu. Benim ise konuşmacıdan öğrenmek istediğim en önemli cevap ise Service Locator pattern, piyasada da anlatıldığı gibi, anti-pattern mı yoksa pattern mı olarak görülmeliydi. Hazır yeri gelmişken sizinle de bu cevabı paylaşayım…

Not: Anti-Pattern tavsiye edilmeyen pattern demek. Nasıl ki pattern dediğimizde denenmiş ve zamanla kalitesi kanıtlanmış kod tasarımları diyorsak, anti-pattern ise bunların tam tersi etki yapacak olan pattern demek.

Kısaca Service Locator…

Öncelikle bilmeyenler için Service Locator nedir bunu anlamaya çalışalım. Biliyorsanız, sonra ki kısımlardan devam edebilirsiniz. Bu pattern abstract factory yada factory method pattern’larına benzetilebilinir. İstediğiniz bir depedency bu pattern sayesinde sınıfınıza getirilir. Kısacası new keyword yerine kullanılıyor diyebilirsiniz. Örnek olarak:

public class AccountCreator{
public void CreateAccount(Account account){
var ldapConnector = ServiceLocator.GetService<ILDAPConnector>();
var connection = ldapConnector.GetConnection();
var acCreator = ServiceLocator.GetService<IActiveDirectoryCreator>();
acCreator.CreateAccount(account);
}
}

Yukarıda ki ServiceLocator.GetService<ILDAPConnector>() bir service locator. Yani ihtiyaç duyduğunuz servisi sizin için bulup getiriyor. Tabi siz başka yerde servislerinizi bu locator’a tanıtmanız gerekiyor. Neyse…

Peki Dependency Injection Kullansaydık…

Eğer Dependency Injection kullansaydık, AccountCreator sınıfımız nasıl görünürdü ona bakalım. Zaten bu farkındalık Service Locator pattern’ı anti-pattern kılan.

public class AccountCreator
{
private readonly ILDAPConnector _ldapConnector;
private readonly IActiveDirectoryCreator _activeDirectoryCreator;
    public AccountCreator(ILDAConnector ldaConnector, 
IActiveDirectoryCreator activeDirectoryCreator)

{
_ldapConnector = ldaConnector;
_activeDirectoryCreator = activeDirectoryCreator;
}
    public void CreateAccount(Account account)
{
var connection = _ldapConnector.GetConnection();
_activeDirectoryCreator.CreateAccount(account);
}
}

Arasında ki farkı görebiliyor musunuz?

Ufak bir soru sorayım: Eğer AccountCreator sınıfını unit test ile test etmek istediğinizde, bu sınıfın yukarıda ki şekillerinden hangisi gibi tanımlanmış olmasını isterdiniz: Service Locator ile mi yoksa Dependency Injection ile mi? Daha anlaşılır olmasından çoğunuz iç sesi Dependency Injection diyecektir, çünkü Service Locator Pattern sınıfın ihtiyaç duyduğu diğer sınıfları ve servisleri, implementasyon detaylarının içinde saklamak sureti ile:

  1. Acaba bu sınıf hangi sınıflara ihtiyaç duyuyor sorusunun cevabını zorlaştırıyor yada imkansız hale getiriyor.
  2. Unit Testing yapmayı çok daha fazla zorlaştırıyor. Belki ServiceLocator’ın GetService() methodunu mock edebilirsiniz, ama bu seferde hangi sınıflara ihtiyaç duyuluyor diye oturup AccountCreator sınıfının içini incelemeniz gerekecek. Kısacası, saçmalıktan seçmeler…

Başka sebepler var mıdır? Olabilir. Ama yukarıda saydığım sebeplerden zaten başlı başına ciddi sorunlar oluşturabilecek sebepler olduğundan yeterli olacaktır diye düşünüyorum.

Bir daha yazımda görüşmek üzere…