Dependency Injection yazımda (loosy coupled) gevşek bağlı sınıfların nasıl dinamik şekilde üretileceğinden çok kısaca bahsetmiştim. Aynı örneğimizi bu sefer dinamik IOC Container ile yapacağız. Üst sınıflara bağlı olan alt sınıfları elle manuel üretmek yerine otomatik olarak ürettirip, IOC Container nesnesinden isteyeceğiz. Bu işlemi XML konfigurasyon ve Kod ile olmak üzere 2 farklı yöntemini de ele alacağız. Bu örneğimizde bir seyahat organizasyonu yapan bir firma var. Bu firma artık araba + bonus şoför kiralamanın pek tercih edilmediğinden dolayı bu seçeneği artık terketmek istiyor. Sadece otobüs + bonus şoför kiralayarak hizmetine devam etmek istiyor. Gelin birlikte örnekleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
public interface IDriver { void Drive(); } public class CarDriver : IDriver { public void Drive() { Console.WriteLine("araba sürülüyor"); } } public class BusDriver : IDriver { public void Drive() { Console.WriteLine("Otobüs sürülüyor"); } } public interface IVehicle { void Passenger(); } public class BusPassenger : IVehicle { public void Passenger() { Console.WriteLine("Otobüs ile geziliyor"); } } public class CarPassenger : IVehicle { public void Passenger() { Console.WriteLine("Araba ile geziliyor"); } } class Organizator { IDriver _driver = null; IVehicle _vehicle = null; public Organizator(IDriver driver, IVehicle vehicle) { _driver = driver; _vehicle = vehicle; } public void MakeTrip() { _vehicle.Passenger(); _driver.Drive(); } } |
Bu tanımlamalardan sonra Projemize Nuget yardımı ile Castle.Windsor u kuruyoruz. Kurulumdan sonra aşağıdaki IOC Container sınıfını yazıyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public static class IoCUtil { private static IWindsorContainer _container = null; private static IWindsorContainer Container { get { if (_container == null) { _container = BootstrapContainer(); } return _container; } } private static IWindsorContainer BootstrapContainer() { // eğer xml konfigurasyon ile çalışmak istiyorsan alt satırda bulunan xmlInterpreteri açınız //if you want xlm configuration is active then remove the comment which is below //return new WindsorContainer(new XmlInterpreter(new ConfigResource("castle"))); /return new WindsorContainer().Register( Component.For<IDriver>().ImplementedBy<BusDriver>(), Component.For<IVehicle>().ImplementedBy<BusPassenger>()); } public static T Resolve<T>() { return Container.Resolve<T>(); } } |
Yukarıdaki kodlarımızda BootstrapContainer methodu dışındakileri sabit şekilde kopyalabilirsiniz kendi projenizde. BootstrapContainer methodunun içini bakarsak xml konfigurasyon tanımlaması ve hemen altında tanımladığımız sınıflar için bir atama işlemi göreceğiz. Kısaca açıklamak gerekirse , Component.For<IDriver>().ImplementedBy<BusDriver>() bu satır şunu demektedir:
Ben senden IDriver arayüzünü implemente eden hangi sınıfı istersem isteyeyim bana yalnızca BusDriver vereceksin demektir. Sonrasında Component.For<IVehicle>().ImplementedBy<BusPassenger>() ise satırda da ben senden IVehicle ile taşınacak yolcu arayüzünden bir sınıf istediğimde o sınıf otobüs ile taşınabilecek yolcu sınıfı olacak. Yani BusPassenger olacak , başka kesinlikle istemiyorum şuan ki ihtiyacım sadece bu. şayet olursa ben ileride onu ayarlarım şimdilik tamamen böyle olacak diyoruz.
Diğer yöntem olan XML için app.config dosyamızı aşağıdaki tanımlıyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" /> </configSections> <appSettings> </appSettings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> <castle> <components> <component id="driver" service="TestProject.IDriver, TestProject" type="TestProject.BusDriver, TestProject"/> <component id="vehicle" service="TestProject.IVehicle, TestProject" type="TestProject.BusPassenger, TestProject"/> </components> </castle> </configuration> |
Yukarıda component olarak tanımladığımız atamalara (map’leme) göz attığımızda kod ile yaptığımızın aynısı aslında. Fark xml ve Sınıfların namespace isimleri ile birlikte yazılması başka bir fark yok.
Son olarak bu tasarımları çağıran program kodumuzu yazalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static class Program { static void Main() { Organizator organizator = new Organizator(IoCUtil.Resolve<IDriver>(), IoCUtil.Resolve<IVehicle>()); // Dependency Injection manual yöntem. // Organizator organizator = new Organizator(new CarDriver(), new CarPassenger()); organizator.MakeTrip(); } } |
Farkettiyseniz eski örnekte organizatöre gidecek sınıfları biz oluştururken şimdi ise o ise IOC Container e yıktık. IOC nin işi bu zaten 🙂 Boşa nuget ten indirmedik .
Artık araba ile seyahat kiralamıyoruz !!
Evet işte bu kadar , ister XML config ile ister IOC Container bootstrapcontainer methodunda manuel olarak atama (mapleme ) yapalım, bizim için artık bir hizmeti açmak kapamak , iptal etmek devreye almak , tek satırdan ibaret hale gelmedi mi ? Geldiyse ne mutlu biz programcılara , yazılım kuralları trafik kuralları gibidir. Umarım faydalı olabilmişimdir
Selam ve dua ile.