Bağımlılığı Ters Çevirme Prensibi (Dependency Inversion)
NOT : Bu yazı Aykut TAŞDELEN’in yakında çıkacak olan UML ve Dizayn Paternleri kitabından alıntıdır izinsiz kullanılamaz.
İlk kez Robert Martin tarafından formüle edilmiş olan bu prensip, yüksek seviyeli sınıfların, aşağı seviyeli sınıflarla doğrudan bir bağının olmamasına dayanır. Böyle bir ilişkinin bağımlılığı arttırmasından dolayı yapılması gereken şeyin araya bir interface veya soyut sınıf sokmak olduğunu öngören bu prensip hakkında daha detaylı bilgi edinmek için; “http://www.objectmentor.com/resources/articles/dip.pdf” adresindeki dokümanı inceleyebilirsiniz. Sözgelimi aşağıdaki sınıfta bu anlamda yanlış yapılmış bir tasarım örneği verilmiştir. FinanceInfo sınıfı içsel olarak yarattığı Finder nesnesiyle veri tabanından kota bilgilerini alıp, yarattığı Renderer nesnesiyle de bu bilgileri Html formatında render etmektedir.
public class FinanceInfo
{
public string GetInfoAsHtml()
{
Finder fnd = new Finder();
StockInfo[] stocks = fnd.FindQuoteInfo(…);
Renderer ir = new Renderer(RenderFormat.Html);
return ir.RenderQuoteInfo(stocks);
}
}
Buradaki sorun; FinanceInfo sınıfının Finder ve Renderer sınıflarını doğrudan kullanmasıyla ortaya çıkan ve bağımlılığı yüksek tasarımdır. Tasarım bu haliyle stokların veri tabanında değil de farklı bir veri kaynağında bulunmak istenmesi ya da verilerin farklı formatlarda render edilebilmesinin istenmesi halinde sorunlar çıkaracaktır.
İşte bu noktada Dependency Inversion prensibi kullanılarak bu bağımlılık yok edilebilir yani tersine çevirilebilir. Herşeyden önce Finder ve Renderer sınıfları doğrudan kullanılmak yerine arayüzleri üzerinden kullanılmalıdır. Bu amaçla IFinder ve IRenderer arayüzleri yazılmıştır. Söz konusu sınıflar bu arayüzleri implemente etmektedir.
public interface IFinder
{
StockInfo[] FindQuoteInfo(…);
// …
}
public interface IRenderer
{
string RenderQuoteInfo (StockInfo[]);
// …
}
public class FinanceInfo
{
private IFinder fnd;
private IRenderer ir;
public FinanceInfo(IFinder f, IRenderer r)
{
fnd = f;
ir = r;
}
public string GetInfoAsHtml()
{
StockInfo[] stocks = fnd.FindQuoteInfo(…);
return ir.RenderQuoteInfo(stocks);
}
}
FinanceInfo bu arayüzler türünde iki veri elemanı içermeli ve ilgili işlemleri bu nesneler üzerinden yapmalıdır ki, böylece ileri de farklı arama ve render etme biçimleri geliştirildiğinde bu sınıf kolayca yeni durumlara adapte edilebilsin.
Aykut TAŞDELEN
C ve Sistem Programcıları Derneği Eğitmeni
