Dependency Injection –
Bağımlılık İletimi
Merhaba
arkadaşlar, gecikmeli de olsa, güncelliğini yitirmemiş bir
konu olan Dependency Injection hakkındaki serinin ikinci
makalesini yayınlıyorum.
Dependency Injection ve Inversion of Control
Kurumsal
Mimari Desenler, her ne kadar farklı alanları adreseler de
[1] , bu desenlerden birisi vardır ki hemen her kurumsal
uygulamada karşımıza çıkar. Basitçe, bir nesnenin bağımlı
olduğu (kabaca, UML de referansı olan) nesnelerin dinamik
olarak çalışma zamanında yapılandırılabilmesine imkan
sağlayan bu desenin adı Dependency Injection desenidir.
Inversion of Control (IoC – Kontrolün geri çevrimi) olarak
adlandırılan bu dinamik yapılandırılabilen bağımlılık
problemi, özellikle kurumsal uygulamaların yaygınlaşmasıyla
birlikte çok sık uygulanan bir çözüm (ki aksi takdirde
desen olması mümkün olmazdı) haline gelmiştir.
Özellikle
günümüzde Servis olarak Yazılım (SaaS) olarak adlandırılan
prensip ile birlikte popülerliğinin zirvesinde olan
Bileşen-temelli geliştirme (CBD-Component Based Development)
yaklaşımının özünü oluşturan tekrar kullanılabilirlik için
tasarımların genelgeçer olmasının ötesinde, çalışma
zamanında nesnelerin dinamik yapılandırılabilmesi de
gereklidir.
Hello
World!…
Internet’te Dependency Injection veya Inversion of Control
şeklinde bir arama yaptığınızda Martin Fowler’in bu konuyu
anlattığı temel makaleye ulaşırsınız. Bu makalede kullandığı
filmleri listelemeye yarayan MovieLister örneği, bir çok DI
ve IoC projesi için Hello World!… niteliğindeki örnektir.
Bu nedenle, ben de bu temel örneği kullanarak bu kavramı
sizlere aktarmaya çalışacağım.
Temel
olarak örneğimiz şöyle: Verinin hangi kaynaktan
geldiğininden tamamen bağımsız olmak üzere bir MovieLister
bileşeni yaratmak istiyoruz.
|
public
class MovieLister
{ …
public
Movie [] MoviesDirectedBy (string
director)
{
IList
allMovies = _movieFinder.FindAll ();
IList
movies = new
ArrayList ();
foreach
(Movie m in
allMovies)
{
if
(director.Equals (m.Director))
{
movies.Add (m);
}
}
return
(Movie []) ArrayList.Adapter
(movies).ToArray (typeof
(Movie)); … } |
Yukarıdaki
örnek koddan da göreceğiniz gibi finder nesnesi
verikaynağına üzerinde çalışmaktadır. İşte, DI problemi
filmleri listeleyen MovieLister sınıfı ile finder
nesnelesinin nasıl ilişkilendirileceği problemidir.
Bu noktada
şunu söyleyebiliriz “Madem finder nesnesinin belirli bir
metodunu ve onun döndürdüğü türü biliyoruz, o zaman finder
sınıfının bu nesnesini bir arayüze taşıyalım ve onu
gerçekleyen sınıfları türeterek MovieLister sınıfında
kullanalım”
|
private
IMovieFinder _movieFinder;
public
MovieLister ()
{
_movieFinder = new SimpleMovieFinder(“myMovies.txt”);
} |
Yukarıda
bu arayüzü, ve bunu gerçekleyen bir sınıf nesnesinin
MovieLister içinde nasıl yaratılıp kullanılabileceğini
görebilirsiniz. Evet, belirli bir arayüzü gerçekleyen bunun
gibi onlarca sınıf yaratabilir ve onları yukarıdaki gibi
kullanabiliriz. Ama unutmayalım, daha tasarım zamanındayız;
çalışma zamanında yukarıdaki nesneler statik olarak
ilişkilendirileceklerdir. Bu anda UML diagramına bakacak
olursak MoveLister sınıfının MovieFinder arayüzüne ve bunu
gerçekleyen sınıfa bağımlı olduğunu görebiliriz. Çalışma
zamanında, bu bağımlılık statik hale gelecektir. O halde
soruyu soralım: MovieLister sınıfını, sadece MovieFinder
arayüzüne bağımlı bırakıp, onu gerçekleyen sınıfla dinamik
olarak nasıl ilişkilendirebiliriz. DI problemini teknik
olarak böyle ifade edebiliriz.

Inversion
of Control – Kontrolün Ters Çevrimi
Yukarıdaki
kodun çalışma zamanındaki davranışını düşünecek olursanız,
bağımlılık ilişkisinde kontrolün MovieLister sınıfında
olduğunu görürsünüz. Yani bu kod ilgili arayüzü gerçekleyen
sınıfın nesnesini yaratarak kullanmaktadır. Bu kontrolün
MovieFinder arayüzü ve onu gerçekleyen sınıfa aktarılması
durumuna Inversion of Control – Kontrolün Ters Çevrimi
diyoruz.
İyi,
Kötü,Çirkin…
DI
probleminin üç çözüm yolu mevcuttur. Birincisi Constructor
injection (type 3), ikincisi Setter injection (type 2) ve
üçüncüsü Interface injection (type 1). Bu çözüm yollar
çeşitli platformlarda gerçeklenmiştir. Bu platoformlardan en
meşhurları pico container (Constructor injection), Spring (Setter
injection) ve Avalon (Interface injection) dur. Bu üç
projeyi de internette ücretsiz olarak bulabilirsiniz. Hemen
belirtmek istiyorum, her üç projenin de .NET türevi
bulunmaktadır.
1)
Constructor Injection
Bu DI
çözüm yolunda MovieLister sınıfının constructor metodunu
aşağıdaki gibi düzenleyip, pico container’in
yapılandırmasında kullanılacak MovieFinder gerçeklemesini
belirterek kullanılır.
|
public
MovieLister (IMovieFinder movieFinder)
{
_movieFinder = movieFinder;
} |
2)Setter
Injection
Spring.NET
tarafından kullanılan bu yöntemde, MovieLister sınıfının
bağımlılık kurduğu MovieFinder nesnesi set metodu
aracılığıyla dışarıdan iletilir. Spring container, xml
aşağıdaki gibi bir yapılandırma ayarıyla çalışma zamanında
bu set metoduna hangi MovieFinder gerçeklemesinin
verileceğini belirler.
|
public
IMovieFinder MovieFinder
{
set
{
_movieFinder =
value;
}
}
…
<object
id="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister,
MovieFinder">
<property
name="movieFinder"
ref="AnotherMovieFinder"
/>
</object>
<object
id="MyMovieFinder"
type="Spring.Examples.MovieFinder.SimpleMovieFinder,
MovieFinder" />
<object
id="AnotherMovieFinder"
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder,
MovieFinder">
<constructor-arg
index="0"
value="movies.txt"
/>
</object> |
3)
Interface Injection
Avalon
tarafından kullanılan bu yöntemde iletim işlemi arayüzler
tarafından gerçekleştirilmektedir. MovieLister sınıfı bu
arayüzü gerçeklemektedir. Avalon framework’ü bu arayüzler
üzerinden, yapılandırma dosyasına gore ilgili sınıfların
nesnelerini yaratıp çalışma zamanında MovieLister’in
kullanımına sunmaktadır. Bir başka deyişle, Spring.NET
container’i tarafından kullanılan set metodlarının yerini
veya pico container tarafından kullanılan constructor
metoduna parameter iletiminin yerini arayuzler almaktadır.
|
…
interface
InjectMovieFinder
{
void
injectFinder(IMovieFinder
movieFinder);
}
… |
Sonuç
Sonuç
olarak, DI veya IoC kullanarak, gerçekten tekrar
kullanılabilir bileşenler yaratılabilir. Çalışma zamanı
davranışının dinamik olarak gerçekleştirilmesi sayesinde,
ilgili container framework’lerin yardımıyla, plugin
mimarileri oluşturabilirsiniz. Gerçekte de bir çok projedeki
plugin mimarileri bu ve benzer yapılarla oluşturulmaktadır.
Bir başka
makalede görüşmek üzere,