25 Aralık 2012 Salı

Design Patterns - Decorator Pattern

Merhaba arkadaşlar,

Sizlerle beraber yaptığımız tasarım desenleri derslerimizin bugünkü konusu en çok bayanların hoşuna gideceğini düşünüyorum :). Bugün dekorasyon tasarım desenini anlatmaya çalışacağız.

Dekorasyon konumuza girmeden önce en son yazdığımız yazının kısa bir özetini geçelim. En son yazımızda singleton tasarım deseninden bahsetmiştik. Singleton tasarım deseni ile şunları yapmayı hedefliyoruz:
  • Bir uygulamanın yaşamı boyunca kullandığı bir sınıfın örneğinin tekil olunmasının istenmesi
  • İstenilen bu örneğin uygulamanın her noktasından erişiminin sağlanması
Singleton tasarım deseni en basit tasarım deseni olarak gözükmesinin nedeni az kod yazılması ve konunun anlaşılırlığının basit olmasından kaynaklanıyor.

Konumuza gelicek olursak dekorasyon kelimesi dilimize fransızcadan geçmiştir. Fransızca da décoration olarak geçmektedir. Dekor etme, süsleme gibi anlamı vardır.


Yukarıda gösterilen güzel araba konumuza çok güzel örnek olacağını düşünüyorum :).

Bizim yapımız da ise nesneleri süslenmesi ve yeni özelliklerinin eklenmesi gibi düşünebilirsiniz. Yukarıda gösterilen şahin arabamızı da(emin değilim doğan da olabilir :) ) süsleme işlemini yapacağız.

Dekorasyon tasarımımız da 4 adet nesne tipi olacaktır. Bunlar aşağıdaki gibidir:

  • Component: Dinamik olarak sorumluluklar ekleyebileceğimiz sınıfa sunulan arayüz veya abstract sınıftır.
  • ConcreteComponent: Sorumluluk ekleyeceğimiz asıl nesnemizdir
  • Decorator: Dekorasyon işlemlerinden sorumlu, değişik dekorasyon şekillerinin üst sınıfıdır. Değişik dekorasyon şekillerini desteklemek için abstract class veya interface olarak tasarlanır.
  • ConcreteDecorator: Dekorasyon işleminin özelliğini barındıran asıl nesnelerdir.
Şimdi konumuzu anlatan uml diagramımıza bir bakalım.


Şimdi ne yaptığımıza bir bakalım. Öncelikle dekorasyonu uygalayacağımız sınıf olan Sahin isimli sınıfımızı görüyorsunuzdur. Sahin nesnemizin özelliklerini dinamik olarak değiştirmek için abstract classtan türettik.

Sahin arabamıza yeni özellikler katacağımız CarDecorator sınıfımızın uml diagramına baktığımızda Car sınıfından türetilmiş ve içinde car sınıfının örneğini barındırdığını görüyoruz. Buradaki amaç modifiye edilmek istenilen aracın dekorasyon sınıfı tarafından sarmalanıp yeni özellikleri de bu sınıftan türeyen dekorasyon sınıflarına bırakılmasıdır.

Biz kapıları geriye doğru açılan bir modifiye olmasını istedik. Bunun için CarDecorator sınıfımızdan SuicideDoorDecorator sınıfını türetti ve yeni özellikler ekledik. Uygulamamızın kodları da aşağıdaki gibi olacaktır.

Uygulamanın Başlangıç Sınıfı
Base Sınıf

Dekorasyonların dinamik olarak uygulanması için türetilen sınıftır.

Sahin arabamız :)
Dekorasyon uygulanacak sınıfımız.


Dekorasyon işlemlerine base olacak sınıfımız.


ve gün sonunda olacak kapı dekorasyon sınıfımız yukarıdaki gibidir.

Kodlara baktığımız zaman, dekorasyon tasarım deseninin amacının nesneye yeni özellikler katmak olduğunu anlayabiliriz.

Bir yazımızın daha sonuna geldik. Bir sonraki yazımız da görüşmek üzere....


19 Aralık 2012 Çarşamba

Design Patterns - Singleton Pattern

Merhaba arkadaşlar,




Uzun bir zamanın ardından yeniden sizlerle birlikte yeni bir konu üzerinde konuşacağız. Blog ile aramın soğumasını önlemek için bugün sıcak bir güneş resmi ile başlangıç yapmak istedim(Anlatacağım konu da da güneşi örnek vericem :Pp).
 
Bir şeyler yapıcaz dedik ama aslında yaptığımız başka insanların yapmış olduğu çalışmaları öğrenmek olacak. Nereden bakarsak bakalım çok hoş olmamakla beraber şu an için elin gavurunun bilgisi bizimkinden önde gidiyor. Öyle kibir yapıpta yok ben öğrenmem, yok ben bilmem deyipte saçma sapan kendini beğenmişlik egosuna girmenin alemi yok gardaşım.
 
Biraz daha muhabbet edelim sonra konumuza başlarız inş. (Direk konuya girmek isteyen kırmızı renkli arkadaşlarımı aşağıdan başlamalarını tavsiye ediyorum :Pp Diğer renkler okumaya devam edebilir :))
 
Uzun bir ara oldu dedik. Nedenini kısaca şöyle bahsetmek gerekirse çalıştığım iş yerindeki organizasyonel değişiklikten dolayı başka bir birime geçiş yaptım. İyi mi oldu kötü mü oldu bilmiyorum ama ileriki dönemlerde daha çok yeni şey öğreneceğimi düşünüyorum inş.  "Tebdil-i mekanda ferahlık vardır" diye bir sözümüzü düşündükçe, bu değişiklikte beni motive ediyor.
 
Günümüz de iş yaşamı boyunca ortalam 10 iş değişikliğinin 2 sini farklı kurum birini kurum içi yaparak 3,5 sene içinde 3 değişiklik sayısına ulaştım. Kalan ömrümüz de ne yaparız bilmiyorum ama hakkımız da en hayırlısı olur inş.
 
Velhasıl hayat devam ediyor ve biz bugün kaldığımız yerden devam etmemiz gerekiyor. 
 
Bugünkü konumuz, tasarım desenlerinin en kolayı ama en güzeli (bana göre :P ) olan singleton tasarım desenini incelemeye çalışacağız.
 
Not: Diğer yazılarımızın başında bir önceki yazımızın özetini yazıyorduk. Uzun bir ara olduğu için özet yerine okumanızı tavsiye ediyorum :)
 .
Singleton kelimesi, tek, tekil gibi anlamlara geldiğini düşünüyorum inş. öyledir :) Singleton tasarım deseninin amacı bir uygulamanın ömrü boyunca belirli bir nesneden sadece bir tane olmasını garanti etmek ve buna her yerden erişimi sağlamaktır.
 
Tanımdan anladığınız gibi konu kulağa çok hoş geliyor. Belli bir sınıfımın örneğini uygulama boyunca sadece 1 kere oluşturulmasını sağlamak amacımız.
 
Giriş cümlem de yazdığım gibi benim uygulamam da bunu güneş ile anlatıcam. Bildiğiniz gibi güneş dünyanın hacminden 1,4122×1027 m³  kadar büyük, çekirdek sıcaklığı ~15,7×106 K   olan bir yıldızdır (O nasıl bir sıcaklıktır :| dini konulara girerdim ama konudan sapmayalım :Pp ). Detaylı bilgi için vikipediye bakabilirsiniz. 
 
Güneş samanyolu galaksisindeki herhangi yıldızdan bir tanedir. Güneşin uygulamamız da temsili olarak göstermek istersek heralde iki tane olması mantıklı gelmez (farklı güneşlerden bahsetmiyoruz bizim güneşimizden bahsediyoruz arada bir iki güzel arkadaşım bana göz kırpıyor gibi :)).
 
Biz de uygulamamız da güneşin kullanılmasını singleton tasarım deseni ile anlatmaya çalışacağız.
 
Yukarıda bahsettiğimiz gibi güneş sınıfından bir örneği uygulama boyunca tek olmasını ve her yerden erişimini sağlayacağız.
 
Multithread kullanılmayan sistemler için aşağıdaki birinci versiyonu inceleyelim.



Yukarıdaki kod bloğunu incelediğimiz de Sun sınıfının constructor metodunun private olduğunu görürüz. Bunun amacı Sun nesnesinin oluşturulmasını dışarıya açmamaktır. Dışarıya açtığımız da zaten nesneden birden çok üretilmesi anlamına gelir.
 
Private olarak tanımlanmış bir diğer alan da ise uygulama boyunca tekil olacak nesnemizin kendisi tutulur.
 
Sınıftan örnek istenildiğinde (GetSun methodu) _sun alanında tuttuğu değer null ise yeni bir örnek oluşturulak bu alana atanır. Daha önce oluşturulmuş ise alan da tutulan değer geri gönderilir.
 
Multithread uygulamalarımız da if bloğunu aynı anda iki farklı thread geçebileceği için birden çok nesnenin ortada gezmesine olanak sağlamış oluruz. Bu gibi durumlar da aşağıdaki kod bloğunu kullanibiliriz.

 
Yukarıdaki kod bloğumuzun ilkinden farklı olarak göze çarpan özelliği lock deyimi ve double check kontrolüdür. Lock deyimi aynı anda birden çok threadin bir kod bloğuna girmesini engeller. Double check ise şöyle açıklayabiliriz.
  • İki thread aynı anda ilk if bloğuna geldi ve ikisi de alanın değeri olmadığı için içeri giriş yaptı (Matrix aklıma geldi birden :)).
  • Bunlardan sadece birini lock bloğunun içerisine alındı.
  • İkinci if bloğunda _sun alanın değeri olmadığı için birinci öncelikli thread içeri girerek nesneyi oluşturdu. İşini bitirdi gitti.
  • İkinci thread lock bloğunun deaktif olmasından faydalanarak kod bloğunun içerisine girerek ikinci if bloğunda karşılaştırma yaptı. artık dolu olan _sun alanının karşılaştırmasında false değeri alarak oluşturulmuş _sun alanını kullanarak yoluna devam etti.
Dilim döndüğünce (yazarken bu deyim çok saçma oluyor) anlatmaya çalıştım. Kısacası bir nesneniz sizin için sanat güneşi ise :)) onun tek olmasını istiyorsanız bu nesnenin tasarımın da singleton tasarım desenini kullanabilirsiniz.
 
Oh sonuna gelebildik. Özlemişiz birşey yazmayı. Ne derece yazdıysak o derece öğrendiğimiz bu çalışmalar kendi içinde basit gözükse de çalışma hayatının olmazsa olmazı "Öğrendiğini uygulamalısın" prensibine çok güzel birer örnek oluyor.
 
Değerli vaktinizi ayırıp okuma zahmetinde bulunan herkese teşekkür ederim. Bir sonraki yazım da görüşmek üzere arkadaşlar...

16 Kasım 2012 Cuma

Design Patterns - Adapter Pattern

Merhaba arkadaşlar,
 
Tasarım desenleri konumuza kaldığımız yerden devam ediyoruz. Bu yazımızda anlatacağımız konumuz adaptör deseni(Adapter Pattern) olarak geçiyor.



Konumuza geçmeden önce bir önceki yazımızı hatırlayalım.

Bir önceki yazımızda Abstract Factory Pattern incelemiştir. Bu desen bize seri nesne üretim yapan fabrikaları üreten üst bir yapıdan bahseder.
 
Konumuza dönersek Adaptör Tasarım ismi insana bir fikir verdiğini düşünüyorum. Adaptörler ne iş yapar diye düşünürsek, sisteme dışarıdan gelen girişleri sistemin anlayacağı şekile dönüştürür. Bu bize ne gibi kolaylık sağlar ? Sisteme girişlerinin standart olması sayesinde adaptörlerin değiştirilebilmesine imkan tanır.
 
Gerçek hayatta buna pek çok örnek var. Bilgisayar şarz cihazları, post cihazları, iett akbil basma cihazı gb.
 
Yazılım da örnek verelim. Hazır kütüphaneleri sistem de kullanırken, kütüphanelere bağımlı kalınmaması için araya adaptörler yazılabilir. Bugünkü örneğimiz de buna uygun şekilde yapalım. Loglama işlemi yapan hazır kütüphane ve kendi loglama mekanizmamızı sistemimize dahil etmeye çalışalım.
 
Uml diagramımıza bakalım.


Uygulamamız da 2 adet loglama yapan sınıf vardır. Bunlardan bir tanesi kendi yazdığımız Mylogger  sınıfımız ve diğeri ise Log4Net kütüphanesidir.

Uygulamamızın kodlarına bakacak olursak;

Adaptör Arayüzü
Log4Net Adaptörü
Kendi Log Kaydetme Sınıfımız
 
Loglama işlemini çağıran sınıf
Log4Net konfigürasyonu app.config
Not: Log4Net konfigürasyonu için assembly.cs sınıfına
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
 satırını eklemeniz gerekmektedir. 
 
Yukarıdaki kodu incelersek prgram sınıfı önce kendi loglama mekanizmasını çağırarak loglama işlemini yapıyor. Daha sonra kullanmak istediği log4net loglama mekanizması için adaptörü kullanıyor.
 
Burada kod geliştirmek istesek başka ne yapılabilir diye düşündüğümüz de loglama mekanizmasını bir factory sınıfından alabiliriz. Bu şekilde üretme işlemini de sistemden soyutlamış oluruz.
 
Dikkat ettiyseniz eğer Log4Net'ten sistemimizi hala tam soyutlamadık. Program sınıfında ILog nesnesini static olarak tanımladık. Bu işlemi de fabrika sınıfında bir Dictionary koleksiyonu içinde tutabiliriz. Loglama işlemi için daha önce gelmeyen bir sınıfın ILog nesnesi oluşturulup koleksiyona ekleriz. Daha sonra gelen aynı sınıf loglama işlemleri için tekrar tekrar değişken tanımlamamıza gerek kalmaz.
 
Arkadaşlar yukarıdaki iki genişletme işlemini kendi sisteminizde deneyebilirsiniz. Bu şekilde pratik yapmış olursunuz(Yazılım dünyasında bir kodu anlamak ve unutmamak istiyorsak kesinlikle örneğini yapmalıyız :)).
 
Bir makalemizin daha sonuna geldik. Adaptör nesnesinin temel özelliği nedir diye sorarsak, bir sisteme monte edilecek farklı sistemler için arayüz oluşturmasıdır.
 
Yanlışlarımız varsa her zaman söylediğim gibi düzeltirseniz memnun olurum. Yazdıklarım bilmediklerimin yanında okyanusta damla gibi olduğunu biliyorum.
 
Okuyan gözlerine sağlık. Görüşmek üzere :)
 

15 Kasım 2012 Perşembe

Design Patterns - Abstract Factory Pattern

Merhaba Arkadaşlar,
 
Bu yazımızda Tasarım Desenleri serimize "Abstract Factory Pattern", Türkçe'si Soyut Fabrika Tasarımı'nı inceleyeceğiz. 
 
Yeni konumuza geçmeden önce bir önceki konumuzu hatırlayalım (Biz cahil insanlar olarak genelde yazdıklarımızı tekrar okumayız ve yazdığımız bilgileri unutmaya terkederiz).
 
Bir önceki konumuz da fabrika tasarımı incelemiştik. Türleri aynı olan ürünlerin tek bir yerden üretilmesini sağlayan bir çözümdü.
 
Soyut fabrika tasarımını anlamak için fabrika tasarımını iyi anlamamız gerekiyor. Soyut fabrika tasarımı fabrika tasarımında gerçekleşen ürün üretimi yerine ürünün üretildiği fabrikaları üretmeyi sağlar. Ne demek şimdi bu ? (Benim gibi bazı arkadaşlar ilk başta bunun anlamını anlamayabilir. Korkacak birşey yok arkadaşlar :))
 
Bir önceki örneğimiz de çikolata yapan fabrikadan bahsetmiştik. İstersek bu örnekten devam edebiliriz ama örnek çeşitliliği adına farklı bir örnek yapmanın daha iyi olacağı kanaatindeyim.
 
2 adet bilgisayar üretme fabrikamız olduğunu düşünelim. Bunların birbirini yiyen iki firma olsun mesela (çok düşünmeye gerek yok:)) Samsung ve Apple(Eşimin telefonu Apple benimki Samsung özgürlüğü tercih ettiğimi düşünüyorum :Pp). 
 
Biz Bir Laptop aldığımız da Laptopun kendisi ve çantası beraber geliyor. Bu fabrikaların amacı benim istediğim model laptop ve çantasını getirmesi. Samsung istiyorsam samsung laptop ve samsung çantam olsun  gb.
 
Bu kadar laf salatalığı yaptıktan sonra bir UML ile ne demek istediğimizi anlatalım.
 
Fabrika Sınıfları
 
Çanta Sınıfları
Laptop Sınıfları
 
Fabrika Kullanma ve Oluşturma Sınıfları
 
Arkadaşlar yukarıdaki uml diagramlarına bakarak şunları çıkartabiliriz.
 
  • Bilgisayar ve Çanta üreten fabrikalarımız ve bu fabrikaların üst sınıfı olan bir sınıfımız vardır.
  • Bilgisayarlar ILaptop arayüzünü implemente etmek zorundadırlar.
  • Çantalar IBag arayüzü implemente etmek zorundadır.
  • Kullanmak istediğimiz model bilgisayar için fabrika üreten bir sınıfımız vardır.
     
 
Kodlarımıza bakalım.
 
ILaptop Arayüzü
 
Apple Laptop Sınıfı
 
 
Samsung Laptop Sınıfı
 
IBag Arayüzü


Apple Çanta Sınıfı

Samsung Çanta Sınıfı
 
Fabrikalara Arayüz Sunan Soyut Sınıf

Fabrika Üreten Sınıf

Apple Fabrikası

Samsung Fabrikası

Bilgisar Almak İsteyen Sınıf
 
Arkadaşlar yukarıdaki kodlarımızı adım adım inceleyelim.
 
  1. Kullanılmak istenilen Laptop markası dışarıdan alınıyor.
  2. Alınan laptop markası fabrikaları üreten sınıfa gönderiliyor(FactoryComputer).
  3. FactoryComputer gelen modele göre ilgili fabrikayı oluşturup geri FactoryBase üst sınıfını gönderiyor.
  4. Kullanılmak istenilen Laptop ve Bag nesneleri için gönderilen sınıfın CreateBag ve CreateLaptop metodları çağrılıyor.
  5. Bu metodlar üst sınıf olan IBag ve ILaptop sınıflarını geriye döndürüyor.
     
Gördüğünüz gibi arkadaşlar fabrika oluşturmak da fabrika kullanmak da gayet basit. Tabiki iyileştirmeler yapılabilir.  Fabrika oluşturma işlemlerini if veya switchlerle kontrol edilmeyebilir. Modellerimiz için oluşturulan laptop ve çantaları biz tek tip yaptık. Bunlar çeşitlendirilebilir.
 
Bir yazının daha sonuna geldik. Bir sonraki yazıda buluşmak üzere :)

14 Kasım 2012 Çarşamba

Design Patterns - Factory Patterns

Merhaba Arkadaşlar,
 
 
Bu yazımızda Türkçesi Tasarım Desenleri olan Design Patterns serisine giriş yapacağız. Aslında aman aman öyle yeni birşey anlatmayacağız. Daha önceki serimiz olan Design Principles kavramlarının baz alarak sıkça rastlanan sorunlara bulunan çözümleri anlatmaya çalışacağız.

Ama önce en son yazımızda ne yazdığımız ile ilgili bilgi vermek istiyorum. (Lost izleyenler flash backleri severler:))

En son yazımızda Dependency Inversion prensibini incelemiştik. Bu prensibte  değişmesi öngörülen alt sınıfların soyutlaştırılmasından bahsettik.

Tasarım Desenleri serimize çoğu üstadın ve arkadaşlarımızın aksine Factory deseni ile başlamak istiyorum(Fabrika diyince insanın içi bir hoş oluyor. Acaba kendimi fabrikatör gibi hissetmemi sağladığından olabilir mi :P ).

Arkadaşlar Fabrika diyince aklımıza ilk gelen şey nedir? Seri üretim yapan, ürettiği şeylerin birbirine benzediği, üretimden sorumlu olduğu bina veya yapılardır.

Bakkala gittiğimiz zaman çikolata almak istediğimizde bize ambalajlı, kapağı olan, cam veya plastik kapta, içi çikolata dolu bir ürün verirler. Ürünün oluşturulması ile ilgili son kullanıcıya iş bırakılmaz.

Yani tekrar bakkala gidelim(Bu sefer başka bakkala gidelim. Ekonomiye can verelim :P) . Çikolota isteyelim. Bize bakkal amca yukarıda yazdığımız ambalaj, kapak, cam, kap, ve çikolotayı verse al kardeşim sen kendin bunu tak, çıkar, koy birşeyler yap sonra yersin. Ne olurdu tepkimiz ?

Factory deseni de işte burada noktaya giriyor. Benim gördüğüm iki noktaya son kullanıcı adına çözüm buluyor.
  • Ürünün üretilmesi
  • Birden çok aynı tip ürünün tek bir noktadan üretilmesi
Şimdi gelelim örnek yapımıza o kadar çikolatalardan bahsettik fabrikamız da çikolata fabrikası olmasında bir sakınca görmüyorum :)

Uml diagramlarımıza bakarsak pek hayırlı bir kod olmadığı ortada :) Cinsleri aynı nesnelerin bir üst sınıftan türetmemek kod hamallığından başka bir şey değil arkadaşlar.
 
Kodumuza gelirsek,
 
Alpella Sınıfımız:
 


Metro Sınıfımız:

Program Sınıfımız:


 


Arkadaşlar kod resimlerinin bazıları bulanık gibi gözüküyor. Yazının sonunda uygulamanın kodlarını ekleyeceğim.

Konumuza dönersek; Farkettiğiniz gibi çikolataları alma ve oluşturma işlemlerini Program sınıfı yapıyor. Yukarıda yazdığımız senaryo da bakkaldan çikolata parçalarını almak ve birleştirmemiz gibi birşeye tekabul ediyor. Bu hem zahmetli bir iş, hem yapılmaması gereken bir iş.

Yukarıdaki kodda bir prensibi de çiğnedik sizce hangisi ? Farkettiyseniz single responsibility prensibini CreateChocolate metodunda çiğnedik. Method hem çikolata oluşturuyor hemde çikolatalar hakkında bilgiyi ekrana basıyor. Bu iki işlemi ayrı metodlara alma işlemini de yeni kodumuza ekleyelim.

 Şimdi kodumuzu düzenleyelim ve bir fabrika deseni kullanarak bu işlemi gerçekleştirelim.

 

 
 
Yeni uml diagramımız yukarıdaki gibi yaparsak sanırım işleri biraz güzelleştirmiş oluruz. Program sınıfı çikolata üretmek için artık uğraşmayacak. ChocolateFactory sınıfından hangi tipten ne kadar istiyor ise o kadar alacak.
 
 

 

Yukarıdaki kod Program sınıfı tarafından ChocolateFactory sınıfından çikolata isteme işlemlerini içeriyor.

Çikolata Fabrikası bu isteği aşağıdaki gibi karşılıyor ve cevap veriyor.



Factory metodu bu şekilde arkadaşlar. Tabi bu kod hala prensiplerimizden bazılarına uymuyor. Open Closed Prensibi burada bizim çakılmamıza neden olur. Sisteme her yeni çikolata eklediğimizde ChocolateFactory sınıfımızı da güncellememiz gerekecek. OCP prensibini uygulamak adına burada reflection yöntemiyle sınıfları ayağa kaldırma işlemi yapılabilir.
 
Umarım size bir fabrikatör olmanın ne kadar kolay olduğunu anlatabilmişimdir :). Eğer benim fabrikamda eksik veya yanlış gördüğünüz bir nokta var ise beni bilgilendirmeniz dolayı memnuniyet duyarım .Her  ne kadar parmaklarımız yazmak için caba gösterse de cahil insanlar olarak illaki bir noktaları kaçırmış olabiliriz.
 
Arkadaşlar uygulamanın kodlarını buradan indirebilirsiniz.
 
Bir sonraki yazıda görüşmek üzere. İyi çalışmalar...
 
 
 

13 Kasım 2012 Salı

Design Prenciples - Dependency Inversion

Merhaba arkadaşlar,

Nesne yönelik programlama adı altında tasarım prensiblerimizi anlatmaya devam ediyoruz. En son anlattığımız konu Interface Segregation prensibiydi.

Her zamanki gibi en son yazdığımız makalemizi hatırlamak adına ne olduğu hakkında kısa bilgi verelim. Interface Segregation prensibi, interfaceleri doğru şekilde tanımlamayı ve implemente edilmesini önerir.

Bu yazımızda anlatacağımız konumuz ise Dependency Inversion prensibidir. Konuya girmeden önce gerçek hayattan birkaç bilgi vermek istiyorum.

Plug and Play denen bir kavram vardır. Bir nesneye başka bir nesnelerin takılıp çalıştırılabilmesi ve iş yaptırılması. Örneklersek eskiden kalma teyplerde kaset takmak, arabanın lastiğini değiştirmek, laptopun bataryasını değiştirmek.


Bunlar olmasaydı ne olurdu diye düşünelim. Bir teyp sadece 1 kaset çalıştıracak, arabanın lastiği değişilemeyecek, laptop bataryalar sökülemeyecek. E peki o zaman ben neden bunları alayım diye içinizden geçiriyorsunuzdur? İşte bu arkadaşlar bu yazımızın konusu :)

Üst sınıflarmız ile alt sınıflarımızı nasıl bağlamalıyız. Nesne yönelimli programlama gelmeden yukarıdaki örneklere insanlar çözüm bulmuş.

Nesne yönelimli programlama buna alt sınıfları soyutlaştırma işlemini yaparak çözüm bulmuş. Hemen uml diagramlarımızla konuyu anlatalım.


Yukarı uml diagramlarında görüldüğü üzere üst sınıf olan Laptop sınıfı alt sınıf olarak Anakart ve Batarya sınıflarına göbekten bağlıdır. Batarya sınıfında yapacağınız değişiklikler Laptop sınıfını direk etkileyebilir. Yukarıdaki diagramları yorumlamaya devam edersek bugün kullandığınız A markalı Anakart yerine B markalı Anakart koymak istediğiniz de Laptopunuzu değiştirmeniz gerekir.

Bu noktada Anakart ve Batarya sınıflarını soyutlaştırırsak laptopumuzun özelliklerini değiştirmemiz  daha kolay olacaktır. Çözüm olarak aşağıdaki uml diagram şeklimiz olabilir mi?


Laptop üst sınıfım artık hangi anakartı veya bataryayı kullandığı o kadar önemli değil çünkü IAnakart ve IBatarya arayüzlerimi uyguladıktan sonra her türlü anakart ve batarya laptopa takılabilir.

Velhasıl arkadaşlar nesne yönelimli programlama bize işlemleri kolaylaştırmak adına imkanlar sunuyor. Bu yazımızla beraber en temel 5 prensibi incelemiş olduk.

Yazdığımız uygulamanın nesne yönelimli bir kod olup olmadığına karar vermek istiyorsanız şu sorulara kendinize sormalısınız.

1- Yazdığınız kod nesne yönelimli ise
2- Tekrar kullanılabilir ise
3- Az bir çaba ile değiştirilebiliyorsa
4- Var olan kodu değiştirmeden genişletilebiliyor ise


güzel bir nesne yönelimli kod yazmışsınız demektir. Eğer bu sorulardan birine cevap veremiyorsanız. Kodunuzu tekrar gözden geçirmenizi tavsiye ederim.

Bir sonraki yazıda buluşmak üzere arkadaşlar :)

Design Prenciples - Interface Segregation

Merhaba arkadaşlar,
 
Tasarım prensipleri anlatımlarımıza kaldığımız yerden devam ediyoruz. En son Liskov Substitution prensibini incelemiştik. LSP prensibini kısaca hatırlamak istersek;
"Alt sınıflardan oluşturulan nesneler üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı göstermek zorundadır" açıklaması yeterli olacağını düşünüyorum.
 
Bugünkü anlatacağımız konu Interface segregation prensibi. Interface segregation prensibinin savunduğu tez şudur arkadaşlar: Interfaceleri sınıflara implemente ederken doğru şekilde implemente edin. Interface üzerinde tanımlanan şartlar, implemente edilen sınıfta kullanılmıyorsa burada bir yanlış var demektir.
 
Ne demek istedik ? Sistemimizde bir interface yazıp bütün şartları bunun içine koyup istenilen sınıflara implemente etmek ilerisi için büyük bir tehlike oluşturur. Sınıflar kullanmadığı her metodlara not implemented exception koymak zorunda kalıcak. Zaten bunun bir adım sonrası OCP ye ters düşen kod yazmaya yöneltecek.
 
UML şemamız ile konuyu anlatmaya çalışalım.
 

 
 
 
IArac interfacemiz olsun. IArac interfacemiz taksi,tir,kamyon gb. nesnelere nasıl davranacağını söyleyecek metodlara sahiptir. Calistir,DorseCikar,DorseTak,Durdur,FarAc,FarKapa,SileceklerCalistir gb. burada farkettiğiniz bir nokta olmalı. Bütün araçlar çalışır,durur,far açılır, far kapanır ama dorsesi olmayan araçlar dorse takamaz ve çıkaramaz. Yukarıdaki uml diagramında görüldüğü gibi taksi nesnesi bu metodlara notimplementedexception fırlatmak zorundadır.
 
Interface segregation kavramı da burada noktaya giriyor. Eğer interfaceniz uygulanan sınıflar tarafından desteklenmiyorsa interfaceinizi bölün.
 
 
 
 
Yukarıdaki uml diagramında IArac arayüzündeki(interface) DorseCikar ve DorseTak metodları IDorseliArac arayüzüne verdik. IDorseliArac arayüzü IArac arayüzünden türettik. Tır ve Kamyon nesnelerine IArac arayüzü yerine IDorseliArac arayüzü implemente ettik.
 
Bu şekilde sınıflar kendilerine dikte edilen metodların hepsini kullanabilir duruma getirdik.
 
Biraz dikkat edersek, şu ana kadar incelediğimiz prensiplerin temelinde şu yatıyor. Sınıflarınız sade olsun, birden çok iş yapmasın, türetme işlemlerini doğru şekilde yapın, interface tanımlamalarını doğru şekilde yapın zaten uygulamanız kendi içinde tutarlı davranacaktır.
 
Hollandalı efsane futbolculardan Johan Cruyff'ın güzel bir sözü vardır futbol ile ilgili:
Futbol basit bir oyundur. Zor olan ise basit oynamaktır.
 
Yazılım dünyasındaki pekçok yazılımı da ben buna benzetiyorum. Kod yazmak basit bir eylemdir. Zor olan basiti yapabilmektir. Kod yazarken kullandığımız programlama dilinin özelliklerini bilip, onun prensiplerine, özelliklerine, davranışlarına hareket ettiğimiz zaman genelde uygulamalarımız doğru çalışır. Eğerki bu konulara hakim değilsek işte o zaman ortaya çıkan uygulamanın intikamı acı olur.
 
Bir sonraki yazımızda görüşmek üzere arkadaşlar :)
 

12 Kasım 2012 Pazartesi

Design Prenciples - Liskov Substitution

Merhaba arkadaşlar,
 
Tasarım prensiblerini anlattığımız en son yazımızda Open - Closed prensibini incelemiştik. Bugünkü yazımızda Liskov Substitution prensibini incelemeye çalışacağız.
 
Liskov Substitution prensibini fikir sahibi Barbara Liskov isimli bir hanım efendidir.
Kendisi hakkında bilgi vermek gerekirse; "Barbara Liskov 2002 yılındaki 29 sayfalık özgeçmişinde araştırma alanlarını işletim sistemleri, dağıtık programlama, programlama dilleri ve programlama metodolojisi olarak belirtmiş. Halen MIT'de çalışan olan Liskov, Amerika'da bilgisayar bilimleri alanında doktora derecesi alan ilk kadındır. Venüs işletim sistemi, CLU programlama dili, nesne tabanlı programlama Liskov'un 1970'lerden beri çalışmalarının ürünlerindendir. Liskov, 2004 yılında John von Neumann madalyası ve 2008 yılında Turing ödülünü almıştır." görüldüğü üzere kendini aşmış bayan mühendis arkadaşlarımıza örnek olacak birisidir.
 
Konumuza dönersek Barbara abla ne diyor ? Barbara abla uygulamalarımız da kullandığımız üst sınıf ve alt sınıflar için birbiriyle uyumlu olmalıdır. Üst sınıfta olupta, alt sınıfın kullanamayacağı bir alan, özellik, method vs. olmamalıdır. Eğer böyle bir durum olursa üst sınıfta tip kontrolü yapmamız gereken durumlar olabilir. Bu da zaten Open - Closed prensibine ters düşer. LSP'ye ters düşen bir implementasyon OCP'ye de ters düşer.
 
Her zamanki gibi konunun daha iyi anlaşılması için basit bir örnek yapalım. 2 adet kalemimiz olsun. Birisi normal kurşun kalem, diğeri dolmakalem. Bunların nesneleştirirsek herkesin aklına aşağıdaki gibi bir resim çıkacağını düşünüyorum.
 

 
Kalem sınıfından türeyen iki adet sınıfımız bulunmaktadır. Buraya kadar herşey çok güzel. İmplementasyon aşamasında KursunKalem ve DolmaKalem nesneleri Kalem gibi davranış gösterebilir.
 
Bir adet sınıf daha bu hiyerarşiye ekleyelim. Kalemimiz MarkerKalem olsun. MarkerKalem ve DolmaKalem'ler bittikleri zaman tekrar doldurulabilir kalemlerdir(Artık markerlarda doldurulmuyor ya neyse. Bizim çocukluğumuz da dolduruyorduk hey gidi günler :)).
 
O zaman ben boya doldur işlemini nereye koymalıyım? İki alt sınıfta bu işlemi yapıyorsa bu işlemi üst sınıf olan Kalem sınıfına mı koymalıyım?
 
Yukarıdaki uml aslında işimizi gayet iyi görür. BoyaDoldur methodunu virtual yapar. KursunKalem sınıfında override ederken metodun içini boş bırakır veya notimplementedexception fırlatırım. Diğer kalem türlerinde yapmak istediğim ne ise onu yaparım.
 
İşte Barbara abla burada bize kızıyor madem alt sınıfın üst sınıfın yerine geçemiyor. O zaman alt sınıfı ya oradan çıkar ya da adam gibi bir ara sınıf koy.
 
Barbara ablamın ilk dediğini yapabiliriz ama bu bizim kalem özelliklerini tekrar tanımlamımıza neden olur. İkinci dediği daha mantıklı gözüküyor. Ara sınıf getirerek BoyaDoldur işlemini bu sınıfa verebiliriz.
 
Şu şekilde olabilir mi?
 
 
Sanki oldu gibi. Artık KursunKalem,MarkerKalem,DolmaKalem nesneleri Kalem nesnesi gibi davranabilir. Bu çözümü ara sınıf koymak yerine bir interface tanımlayıp DolanKalemlere uygulatılabilir.
 
İşte bu şekilde yapınca Barbara abla bize mutlu bir tebessüm gönderiyor afferim cahil çocuklarıma diyor:)
 
Konuyu parmaklarımızın yazdığı kadar anlatmaya çalıştık arkadaşlar. Bir sonraki yazımızda görüşmek üzere :)
 
 

Open Closed Prensibine Benzeyen Güzel Ülkemin Eğitim Sistemi

Merhaba arkadaşlar,
 
Yazılım diyince herkesin aklına farklı farklı şeyler geliyor. Bilgisayar, program, microsoft, işlemci, ekran, c#,wcf, business, klavye, uykusuz geceler, visual studio vs.
 
Benim de aklıma üniversite yıllarımda aldığım dersler geliyor. Okulumu eleştirmek adına birşey söylemek istemiyorum. Her kurum kendi kapasitesi kadar bilgi verebiliyor. Yalnız burada temel bir sıkıntı var; Okul hayatında öğrenilen bilgilerin iş hayatına geçişi :)
 
Bu konu gerçekten bir tez konusu olur kanaatindeyim. Neden ? Çünkü okul hayatında öğrenilen teorik bilgiler eğer kullanılmıyorsa veya kullanıldığında işe yaramıyorsa burada bir sorun var demektir.
 
Üniversitelerimizin kaliteli insanlar piyasaya sürmemesi, insanların kalitesiz olmasından ziyade sistemin kalitesiz olmasından kaynaklı olduğunu düşünüyorum.
 
Üniversitelerdeki derslerin çok saçma olduğunu düşünmüyorum. Mühendislik eğitimi için alınması gereken dersler. Peki o zaman sorun nedir? Sorun şu üniversitedeki çoğu teorik bilgiler kullanılmıyor. Bilgisayar Mühendisi eğitimi alıyoruz bilgisayarın içini dahi açmıyoruz. Makina Mühendisi eğitimi alıyoruz makina görmüyoruz vs. uzatılabilir.Herkes kalem tüketiyor ama ne için tüketiyoruz kimse bilmiyor :)
 
 
 
Sistem bu kadar kendi içinde çelişirken insanları başarılı başarısız diye sınıflandırmak ne kadar doğru oda ayrı bir konu.
 
Geçen yazımızda sizlerle Open - Closed prensibini işlemiştik. Prensip şunu diyordu uygulamalarınız genişlemeye imkan versin, genişlerken eski kodların mümkün olduğu kadar değişmesin hatta hiç değişmesin :). Çünkü her değiştirme işlemi için uygulamaları test etme ve değişiklik yapma maliyetini yanında getiriyor.
 
Yukarıda anlatmak istediğim eğitim sistemi de işte tam burada çatlıyor :). Eğitim sistemimizi geliştirmek istiyorlar ama eskiden tecrübe edilmiş insanların bir şekilde uyum sağladığı doğruları da değiştiriyorlar. Sonuç insan kirliliği (Kod kirliliği :)) 
 
Sistem her iki senede bir genişletilmek adına temellerinden değiştiriliyor. Zaten piyasadaki insanların anlayış, düşünme ve olaylara bakış açısı farklarındaki etkenlerinden birisi sistemin çizdiği farklılıklardan kaynaklandığını düşünüyorum.
 
Velhasıl bir yazılım prensibini güzel ülkemin sistemine benzettim ya helal olsun ya bana laa :) Bunu da ancak benim gibi bir cahil yapar :Pp
 
Bu kadar gevezelik yeter sistem düzeltilmeyi beklerken burada konuşmanın alemi yok...

10 Kasım 2012 Cumartesi

Design Prenciples - Open Closed


Merhaba arkadaşlar,
Kasım ayının ortalarına doğru ilerlerken kış mevsimi de kendini yavaş yavaş gösteriyor. Dışarıda yağmurun etkisi ne çok fazla ne az, hani derler ya ahmak ıslatan bir yağmur işte ondan yağıyor.
(Dikkat ettim çalışma masamın önündeki perdeyi açma gereği hissetmemişim. Sanırım dışarıdaki havanın benim için vereceği mutluluğun farkında değilim.)

İnsanlar genelde güneşli havaya iyi derken, yağmurlu veya kapalı havaya kötü(kapalı) derler. Ben buna katılmıyorum. Her havanın kendine özgü güzelliği olduğunu düşünüyorum. Her zaman yaptığımız gibi subjektif görüşlerimizi objektifmiş gibi sunuyoruz...

Böyle bir havanın insana vereceği enerji kimine göre az olacak ama bize göre çok olduğunu düşünerekten konumuza adım atalım.

En son yazımızda tasarım prensiblerinden single responsibility konusuna değinmeye çalışmıştık. Kısaca hatırlamak istersek single responsibility kavramı, sınıfların sadece tek bir amacı olması gerektiğini savunuyordu.

Bugün Open-Closed kavramını dilimiz döndüğünce, parmaklarımız yazdığınca değinmeye çalışacağız.

Open-Closed kavramı çoğu yazılımcının dikkat etmediği bir konudur. Basitce anlatmak gerekirse yaptığımız uygulamanın genişletilebilirliği olmalı fakat eski kodlar değiştirilmemelidir. Bu ne demek ?? (Hiçte basit olmadı ya neyse :))

Şöyle anlatayım yönetici sınıfların kullanmak istediği alt nesnelerin oluşturması ve kullanmasını çoğu zaman if, switch deyimleri ile yaparız. Daha sonra yeni eklenen nesneler eklendiği zaman  if veya switch deyimlerine eklemeler yaparız. İşte tam burası Open-Closed kavramının Closed kısmını bozuyor. (Uygulamalarımız da ne kadar if kullanırsak uygulamanın genişletilebilirliği zorlaşacağı gibi anlaşılırlığı da azalacaktır.)

Şimdi buna programsal bir örnek verelim. Elimizde şifreleme algoritmaları olan DES ve 3DES algoritmaları ve bu algoritmaları kullanan bir program olduğunu düşünelim. Biz uygulamamızda  DES ve 3DES algoritmalarını kullanarak Open Closed prensibini uygulamaya çalışacağız.

Elimizde aşağıdaki şekildeki gibi bir diagram olduğunu düşünelim.
 
 
 Amacımız  Des ve 3Des algoritmalarını kullanarak şifreleme ve şifre çözme işlemleri olduğunu düşünürsek yukarıdaki yapı aslında işimizi görür gibi gözüküyor.


Base sınf EncryptBase aslında pek bir iş yapmıyor. Yaptığı işlem encrypt ve decrypt işlemleri için gönderilen DesEncrypt ve ThreeDesEncrypt sınıflarını ortak bir noktada göndermek için oluşturulmuş. Tabi bu bizim için kötü bir kodlama. EncryptManager sınıfının kodunu incelersek.


using System;
 
namespace EncryptLibrary
{
    public class EncryptManager 
    {
        EncryptBase _encrpytBase = null;
        public EncryptBase EncryptBase{
            get
            {
                return _encrpytBase;
            }
            set
            {
                _encrpytBase = value;
            }
        }
 
        public EncryptManager(EncryptBase obj)
        {
            _encrpytBase = obj;
        }
 
        public EncryptManager()
        {
 
        }
 
        public string EncryptData(string originalData)
        {
            if (_encrpytBase is DesEncrypt)
            {
                return ((DesEncrypt)_encrpytBase).Encrypt(originalData);
            }
            else if (_encrpytBase is ThreeDesEncrypt)
                return ((ThreeDesEncrypt)_encrpytBase).Encrypt(originalData);
            else
                throw new Exception("Bilinmeyen bir şifreleme algoritması");
        }
 
        public string DecryptData(string originalData)
        {
            if (_encrpytBase is DesEncrypt)
                return ((DesEncrypt)_encrpytBase).Decrypt(originalData);
            else if (_encrpytBase is ThreeDesEncrypt)
                return ((ThreeDesEncrypt)_encrpytBase).Decrypt(originalData);
            else
                throw new Exception("Bilinmeyen bir şifreleme algoritması");
        }
    }
}

Yukarıda yazdığımız kod aslında bizim işimizi halleder. Peki o zaman bu prensip neye kızıyor ? Kızdığı şey şu arkadaşlar bu kütüphaneye ben yeni bir şifreleme algoritmasını eklemek istediğim de eğer bu sınıflara dokunuyorsam, bu sınıflar tekrar test edilmeli ve gözden geçirilmelidir.

İşte burada nesne yönelimli uygulamanın en güzel 3 özelliğinden biri çok biçimlilik devreye giriyor ve bize "Dur kardeşim sen niye böyle ifler felan yazıyorsun? Ben senin için run time da nesneleri değişik davrandırabiliyorum. Neden benim bu özelliğimden faydalanmıyorsun ?" diyor.

(Ah böyle dese ne güzel olur. Bizim gibi cahiller sağı solu tırmalamazdık:( )

Şimdi uygulamayı biraz değiştirelim ve bakalım nasıl birşey ortaya çıkacak.

 

 Öncelikle base sınıfını abstract sınıf olacak şekilde değiştirelim. EncryptManager sınıfını da aşağıdaki gibi değiştirelim.




using System;
 
namespace EncryptLibrary
{
    public class EncryptManager
    {
        EncryptBase _encrpytBase = null;
        public EncryptBase EncryptBase
        {
            get
            {
                return _encrpytBase;
            }
            set
            {
                _encrpytBase = value;
            }
        }
 
        public EncryptManager(EncryptBase obj)
        {
            _encrpytBase = obj;
        }
 
        public EncryptManager()
        {
 
        }
 
        public string EncryptData(string originalData)
        {
            return _encrpytBase.Encrypt(originalData);
        }
 
        public string DecryptData(string originalData)
        {
            return _encrpytBase.Decrypt(originalData);
        }
    }
}
 
 Yukarıda başta söylediğimiz işlemi yapan bir kod bulunuyor. Ne demek istiyorum. Bu uygulamaya istediğimiz şifreleme algoritmasını ekleyelim EncyptManager sınıfına dokunmamız gerekmiyor. Yapmamız gereken tek şey ekleyeceğimiz şifreleme algoritmasını EncryptBase sınıfından türetmemiz gerekiyor.
 
Burada abstract sınıf yerine interface de kullanabiliriz. Bunu sizin seçiminize bırakıyorum.

Uygulamanın kodlarına Open Closed indirebilirsiniz.

Okuyan gözleriniz dert görmesin :)