Bugün benim doğum günüm(31/12/1985) 25. yaşıma ufaktan ayak basmış bulunuyorum...
Her bir yıl biterken insanların gelecek yeni yıldan bir takım beklentileri olur. Aslında insanların ihtiyacı olan tek şey sadece yeni bir başlangıç noktasıdır. Gerçekten öyle mi peki ?
Öyle bir toplum olduk ki, yaptığımız hemen her şeyden kısa bir süre sonra pişmanlık duyuyoruz. Pişmanlık derecesinde olmasa bile birçok şeyden sonra keşke ile başlayan cümleleri çok sık kurar olduk. Keşke şunu yapmasaydım, keşke şunu demeseydim...
Keşkeci bir insan olmanın altında yatan en büyük neden ise; kendine güven eksikliğidir.
Zamanı geri alamadığımız için bize gereken tek şey, zamanda yeni bir başlangıç noktasıdır ki, çoğu insan böyle zamanları önemli günler olarak seçer. İşin komik yanı, her yeni başlangıçtan sonra yapılan şeyler yine aynı keşkelere neden olacak şeyler olur. Çünkü değişen kişi değil sadece başlangıç noktasıdır. Bize gereken ise aslında yeni bir başlangıç noktası değil, hayatımızda yaşadığımız her saniyeden bile çıkarım yapabilme yeteneğidir. Diğer bir deyişle, yaptıklarımızdan ders alabilmektir...
Şimdi 2010 'un ilk gününü, önceki tüm yılların ilk günleri gibi hayatında fark yaratacak yeni bir başlangıç noktası olarak görmek yerine, hayatının başlangıcını doğduğun an olarak kabullen ve bugüne kadar keşke dediğin herşeyden birer çıkarım yap. Hayatında fark yaratmak yerine sadece senin olan hayatı yaşa. Eminim bugüne kadar denemediğin tek şey bu, dene...
Her başlangıç yeni bir son demekse, bir kere başla...
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://aydinunlu.blogspot.com
31 Aralık 2009
16 Kasım 2009
Open Source Nedir ? Ne Değildir ?
Open Source (Açık Kaynak) kavramı özellikle ülkemizde çok fazla basite indirgenmiş bir kavramdır. Aslında open source dediğimiz şey gerçekte çok basit bir kavramdır. Fakat benim ilk cümlemde "basite indirgenmiş" diyerek anlatmak istediğim şey; kavramın içinin boşaltılmasıdır...
Open Source kavramı bugüne kadar hep yazılım geliştirme süreci ile birlikte kullanılan bir kavram olarak karşımıza çıktı. Zaman zaman birileri bu kavramı karşımıza böyle çıkardı ve bizde karşımıza her sunulan şeyi kabullendiğimiz gibi bunu da hep bu şekilde kabullendik. Fakat gerçekte open source denen kavramı sadece yazılım geliştirme gibi bir alan ile sınırlandırmak bu fikirsel akıma tamamen haksızlık yapmak demektir.
Open source' ün ne olduğuna geçmeden önce bugüne kadar bize anlatılanlardan bahsetmek gerekirse; en basit hali ile kaynak kodu açık bir şekilde yazılım geliştirme sürecidir diyebiliriz. İlk bakışta herhangi bir mantığa dayandıramadığımız bu süreç üzerine biraz düşününce aslında son derece iyi niyetli bir düşünce olduğunu anlıyoruz. Buraya kadar bir sorun yok zaten. Fakat sorun bu kavramı bu kadar sığ bir şekilde açıklayıp gerisini getirememekten kaynaklanıyor.
Bu durumu neden bir sorun olarak gördüğüme gelirsek eğer şunu söyleyebilirim ki;
bu kavramın içi sığ tutulduğu sürece, open source kavramı kendi ideolojisine tamamen zıt olan farklı ideolojilerin(örneğin kapitalizm gibi) kendi çıkarları doğrultusunda onu sömürmesi devam edecektir. Bu cümleden sonra biraz durup düşünmek gerekiyor sanırım. Çok ufak bir örnek vermek gerekirse, günümüz de tamamen kar elde etmeye odaklanmış ulusararası bir X firması , 2-3 tane open source projeye imza atıp, bakın biz de open source' e destek veriyoruz imajı yaratarak programcıları kendi cephesine çekmeye çalışmaktadır. Üstelik bu çabalar özgür düşüncenin hakim olması gereken üniversite salonlarında gerçekleştirilmektedir. Farklı bir örnek daha vermek gerekirse benzer girişimler sanat alanında da görülebilmektedir. Bir çok küresel firma bir yandan çevreyi kirleterek Dünya'yı yaşanmaz bir hale getirirken bir yandan da sanata destek veriyoruz imajı yaratmaya çalışır. Peki bunu neden yaparlar? Bu sorunun cevabı tamamen ayrı bir yazı konusudur, dolayısıyla bu bölümü burada bitirerek open source' ün bize anlatılmayan kısımlarına değinmek istiyorum.
Open source için öncelikle söylenmesi gereken ilk şey bence; asla ama asla sadece yazılım geliştirme süreci ile alakalı bir kavram olmadığıdır. Aksine open source' ü hayatın her alanında görebiliriz. Yeter ki doğru açıdan bakalım.
Open source, insanların hayata bakış açıları ile örtüşen bir fikir akımıdır. Hayattan tek beklentisi sadece kendini kurtarmak olan ve öğrendiği herşeyi kendisine saklayan insanların sahip olamayacağı bir bakış açısıdır.
Open source, tüm insanlığı daha iyiye ve daha doğruya götürecek bir fikir akımıdır. Dolayısıyla paylaşımcı ve pozitif bir bakış açısıdır. Bir bilim adamının bir hastalığa karşı bulduğu bir ilacın formülünü diğer bilim adamları ile paylaşması da özünde bir open source 'e destek hareketidir. Bir programcının geliştirdiği bir mimariyi insanlara anlatmasıda...
Open source'e bir programcı bakış açısıyla bakarsak eğer ilk olarak, sadece kaynak kodu açık bir şekilde yazılım geliştirmek demek değildir diyebiliriz. Bu durum sadece yapılması gereken adımlardan biridir. Önemli olan open source denen kavrama neden ve nasıl sadık kalmanız gerektiğidir. Örneğin open source olmayan araçlar ile open source' e destek verilebilir mi ? Bu sorunun cevabının zaman zaman değişkenlik gösterebileceğine inandığım gibi genel olarak bence evet diyebilirim. Çünkü işin özünde insanlara bir fikir vermek, bir fikri paylaşmak vardır. Eğer yaptığınız işle insanlara bir fikir veremiyorsanız bunun sizden başka kimseye bir faydası yoktur. Bu da open source kavramına tamamen terstir.
Örnek vermek gerekirse bir içerik yönetim sistemini sadece açık kaynak kodlu şekilde geliştirirken insanlara bir fikir veremiyorsanız bunun hiç bir anlamı yoktur. Hatta bence bu tamamen bir zaman kaybıdır. Burada bence bakış açısı şu şekilde olmalıdır; siz veriye erişim için bir mimari geliştirmiş olabilirsiniz ve bunu bir içerik yönetim sistemine entegre şekilde örnekleyerek insanlara sunarsınız. İşte bunu yaptığınız zaman tüm programcılara bir fikir vermiş olursunuz. Burada ki amacınız içerik yönetim sistemi değil, veriye erişim mimarisidir. İçerik yönetim sistemide bu amacın anlatılmasını kolaylaştırmak için kullanılan bir araçtır sadece...
Bu anlattıklarımın hepsi bir yana open source 'de gözden kaçan bir nokta daha vardır ki oda, geri bildirimdir. Geri bildirim sayesinde sizin paylaştığınız fikirler insanlar tarafından yorumlanır ve bir şekilde size geri döner. Bu sayede siz kendi fikirlerinizin ne kadar doğru veya ne kadar yanlış olduğunu çok net bir şekilde öğrenir ve kişisel gelişiminizi çok olumlu bir şekilde sürdürebilirsiniz. Kendi fikirlerini kimseyle paylaşmayan bir insan neyin doğru neyin yanlış olduğunu asla ama asla öğrenemez bence.
Tekrar etmek gerekirse, open source; sadece kaynak kodu açık bir şekilde yazılım geliştirme süreci demek değildir.Aksine open source' ü hayatın her alanında görebiliriz. Yeter ki doğru açıdan bakalım.
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Open Source kavramı bugüne kadar hep yazılım geliştirme süreci ile birlikte kullanılan bir kavram olarak karşımıza çıktı. Zaman zaman birileri bu kavramı karşımıza böyle çıkardı ve bizde karşımıza her sunulan şeyi kabullendiğimiz gibi bunu da hep bu şekilde kabullendik. Fakat gerçekte open source denen kavramı sadece yazılım geliştirme gibi bir alan ile sınırlandırmak bu fikirsel akıma tamamen haksızlık yapmak demektir.
Open source' ün ne olduğuna geçmeden önce bugüne kadar bize anlatılanlardan bahsetmek gerekirse; en basit hali ile kaynak kodu açık bir şekilde yazılım geliştirme sürecidir diyebiliriz. İlk bakışta herhangi bir mantığa dayandıramadığımız bu süreç üzerine biraz düşününce aslında son derece iyi niyetli bir düşünce olduğunu anlıyoruz. Buraya kadar bir sorun yok zaten. Fakat sorun bu kavramı bu kadar sığ bir şekilde açıklayıp gerisini getirememekten kaynaklanıyor.
Bu durumu neden bir sorun olarak gördüğüme gelirsek eğer şunu söyleyebilirim ki;
bu kavramın içi sığ tutulduğu sürece, open source kavramı kendi ideolojisine tamamen zıt olan farklı ideolojilerin(örneğin kapitalizm gibi) kendi çıkarları doğrultusunda onu sömürmesi devam edecektir. Bu cümleden sonra biraz durup düşünmek gerekiyor sanırım. Çok ufak bir örnek vermek gerekirse, günümüz de tamamen kar elde etmeye odaklanmış ulusararası bir X firması , 2-3 tane open source projeye imza atıp, bakın biz de open source' e destek veriyoruz imajı yaratarak programcıları kendi cephesine çekmeye çalışmaktadır. Üstelik bu çabalar özgür düşüncenin hakim olması gereken üniversite salonlarında gerçekleştirilmektedir. Farklı bir örnek daha vermek gerekirse benzer girişimler sanat alanında da görülebilmektedir. Bir çok küresel firma bir yandan çevreyi kirleterek Dünya'yı yaşanmaz bir hale getirirken bir yandan da sanata destek veriyoruz imajı yaratmaya çalışır. Peki bunu neden yaparlar? Bu sorunun cevabı tamamen ayrı bir yazı konusudur, dolayısıyla bu bölümü burada bitirerek open source' ün bize anlatılmayan kısımlarına değinmek istiyorum.
Open source için öncelikle söylenmesi gereken ilk şey bence; asla ama asla sadece yazılım geliştirme süreci ile alakalı bir kavram olmadığıdır. Aksine open source' ü hayatın her alanında görebiliriz. Yeter ki doğru açıdan bakalım.
Open source, insanların hayata bakış açıları ile örtüşen bir fikir akımıdır. Hayattan tek beklentisi sadece kendini kurtarmak olan ve öğrendiği herşeyi kendisine saklayan insanların sahip olamayacağı bir bakış açısıdır.
Open source, tüm insanlığı daha iyiye ve daha doğruya götürecek bir fikir akımıdır. Dolayısıyla paylaşımcı ve pozitif bir bakış açısıdır. Bir bilim adamının bir hastalığa karşı bulduğu bir ilacın formülünü diğer bilim adamları ile paylaşması da özünde bir open source 'e destek hareketidir. Bir programcının geliştirdiği bir mimariyi insanlara anlatmasıda...
Open source'e bir programcı bakış açısıyla bakarsak eğer ilk olarak, sadece kaynak kodu açık bir şekilde yazılım geliştirmek demek değildir diyebiliriz. Bu durum sadece yapılması gereken adımlardan biridir. Önemli olan open source denen kavrama neden ve nasıl sadık kalmanız gerektiğidir. Örneğin open source olmayan araçlar ile open source' e destek verilebilir mi ? Bu sorunun cevabının zaman zaman değişkenlik gösterebileceğine inandığım gibi genel olarak bence evet diyebilirim. Çünkü işin özünde insanlara bir fikir vermek, bir fikri paylaşmak vardır. Eğer yaptığınız işle insanlara bir fikir veremiyorsanız bunun sizden başka kimseye bir faydası yoktur. Bu da open source kavramına tamamen terstir.
Örnek vermek gerekirse bir içerik yönetim sistemini sadece açık kaynak kodlu şekilde geliştirirken insanlara bir fikir veremiyorsanız bunun hiç bir anlamı yoktur. Hatta bence bu tamamen bir zaman kaybıdır. Burada bence bakış açısı şu şekilde olmalıdır; siz veriye erişim için bir mimari geliştirmiş olabilirsiniz ve bunu bir içerik yönetim sistemine entegre şekilde örnekleyerek insanlara sunarsınız. İşte bunu yaptığınız zaman tüm programcılara bir fikir vermiş olursunuz. Burada ki amacınız içerik yönetim sistemi değil, veriye erişim mimarisidir. İçerik yönetim sistemide bu amacın anlatılmasını kolaylaştırmak için kullanılan bir araçtır sadece...
Bu anlattıklarımın hepsi bir yana open source 'de gözden kaçan bir nokta daha vardır ki oda, geri bildirimdir. Geri bildirim sayesinde sizin paylaştığınız fikirler insanlar tarafından yorumlanır ve bir şekilde size geri döner. Bu sayede siz kendi fikirlerinizin ne kadar doğru veya ne kadar yanlış olduğunu çok net bir şekilde öğrenir ve kişisel gelişiminizi çok olumlu bir şekilde sürdürebilirsiniz. Kendi fikirlerini kimseyle paylaşmayan bir insan neyin doğru neyin yanlış olduğunu asla ama asla öğrenemez bence.
Tekrar etmek gerekirse, open source; sadece kaynak kodu açık bir şekilde yazılım geliştirme süreci demek değildir.Aksine open source' ü hayatın her alanında görebiliriz. Yeter ki doğru açıdan bakalım.
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Makale,
Open Source,
Sadece Yazıyorum
07 Ekim 2009
SOLID Principles e-book
Kısa bir süre önce yazıp yayınladığım SOLID Principles adlı yazı dizisindeki 6 makalemi toplayıp pdf formatında ufak bir e-book olarak derledim. İnternetin olmadığı durumlarda da okuyabilmek veya elinin altında bulunmasını isteyen arkadaşlar buradan download edebilirler.
Etiketler:
Desing Principle,
Makale,
SOLID
17 Eylül 2009
Entity Framework için Singleton Entity Modeli Geliştirmek
Merhaba arkadaşlar,Kısa bir süre önce bitirdiğim SOLID Patterns yazı dizisinden sonra kısmen daha teknik bir yazı yazmanın güzel olacağını düşündüm. Hemen ardından performans odaklı bir çözüm sunmak için bu yazıyı yazmaya karar verdim...
Bu yazımızın konusu, entity framework ile geliştireceğimiz uygulamalarda ki, özellikle büyük bir entity nesnesi üzerinde çalışırken, bu nesnenin sürekli new ile örneklenmesinin önüne geçmek. Böylece büyük bir nesnenin birden çok örneğinin sürekli örneklenmesi ile oluşacak bellek kaybının yaşanmasını engellemiş olacağız. Bunu yaparken de basit ve kullanışlı bir tasarım deseni olanı Singleton desenini kullanacağız.
Konumuz singleton desenini içerdiği ve entity framework odaklı olduğu için öncelikle bu konuları en azından giriş seviyesinde bilmeniz gerekiyor. Singleton desenine yazı içinde kısaca değineceğim ve entity framework' ün nasıl kullanıldığını da resimli bir şekilde anlatacağım. Bunun dışında bu anlatım çok fazla detaylı olmayacağı için, size çok faydasını dokunacağından emin olduğum ado.net' in resmi web sitesinde yayınlanan How Do I video serisini izlemenizi tavsiye ediyorum. Singleton ve diğer bir çok OOP kavramı için de OODesign sitesini ziyaret edebilirsiniz.
İşe kısaca Entity Framework 'ü ve Singleton desenini tanıyarak başlayalım isterseniz...
Veritabanı uygulamaları geliştirirken karşılaştığımız en büyük sorun, kuşkusuz veritabanı nesnelerinin uygulama geliştirme tarafında birer nesne olarak modellenmesidir. Bunun için bir çok farklı platform için geliştirilmiş çeşitli araçlar vardır. En bilinen örnek kuşkusuz Java için geliştirilmiş olan Hibarnate' in, .net uyarlaması olan NHibarnate' tir. EntityFramework 'ün de kavramsal olarak NHibarnate 'den hiç bir farkı yoktur. Yani EF'de özünde sadece bir ORM aracıdır. Yaptığı şey ise veritabanınızı olduğu gibi object olarak modellemektir. Bütün ORM araçları da bunu yapar aslında. Böylece siz veritabanı, tablolar, alanalar, stored procedure'ler gibi hemen hemen bütün veritabanı varlıkları üzerinde, saf OOP temelli uygulama geliştirme süreci izleyebilirsiniz. Bu da kısaca OOP' nin tüm nimetlerinden yararlanmak demektir. Nitekim Singleton deseninin de Object Oriented temelli bir tasarım deseni olduğunu düşünürsek bu nimetten faydalanmak ta en büyük hakkımız sanırım :)
Entity Framework 'ün görevinin bir veri tabanını object olarak modellemek olduğunu söyledik. Bu bağlamda şöyle bir sorun var ki, eğer veritabanı varlıksal açıdan çok büyükse, EF' nin oluşturacağı entity nesneside çok büyük olacaktır. Veritabanının varlıksal açıdan büyük olması ile söylemek istediğim şey ise, tablo, kolon, stored procedure gibi veritabanı varlıklarının çok fazla olmasıdır. Böyle bir entity nesnesinin her kullanmak istediğimiz zaman new ile örneklememiz gerekeceği için sürekli ram üzerinde aynı nesnenin birden fazla örneği yer işgal edecektir. Bu durum da ram 'in gereksiz yere tüktelimesi demektir. Özellikle web uygulamalarında sorun olacak bir durumdur bu. Singleton tasarım desenide işte tam bu noktada devreye giriyor ve bizi bu yükten kurtarıyor. Nasıl mı ?
Şöyle ki; Singleton tasarım deseninin dayandığı temel ilke; bir nesnenin, içinde bulunduğu uygulamanın yaşam süresi boyunca, sadece 1 kez new ile örneklenmesini sağlamaktır. Bir başka deyişle, siz bir nesneyi 1 kere new ile örnekledikten sonra oluşacak tüm örnekleme isteklerinde, aynı nesne bir kez daha örneklenmeyecek ve var olan nesne kullanılacaktır.
Bu açıklamalardan sonra artık örneğimize geçebiliriz.
Örneğimiz "SingletonEF" adında bir konsol uygulaması olacak.Fakat siz web ve Windows uygulamalarında da kullanabilirsiniz tabiki. Bunun dışında kullanacağımız veritabanı da AdventureWorks olacak. Uygulamayı oluşturduktan sonra EF ile entity nesnemizi oluşturabiliriz. Bunları kısaca resimli olarak görelim hemen.
1. Uygulamaya sağ tıklayıp, Add New Item diyelim. Açılan pencereden ADO.NET Entity Data Model 'i seçelim ve adına EntiyModel diyelim.

2. Ardından açılan pencereden Genereate From Database 'i seçelim ve next diyelim.

3. Ardından açılan pencereden New Connection ile bağlanmak istediğimiz veritabanını seçelim ve onaylayıp aynı pencereye döndükten sonrada entity 'mize isim olarak DataContext adını verip next ile ilerleyelim. (Burada verdiğimiz isim C# tarafında programlamada kullanacağımız isim olacaktır.)

4. Ardından açılan pencerede modellenmesini istediğimiz veritabanı varlıklarını seçip Finish butonuna basalım.

Bu işlemleri gerçekleştirdikten sonra entity objemiz projemize dahil edilecektir. Bu işlem sırasında çeşitli referanslar eklenmekle birlikte , solution explorer penceresinde eklenen entity 'mizi görebilirsiniz. EntityModel.Designer.cs kod dosyasında da, Visual Studio' nun entity için dinamik olarak oluşturduğu kodları görebilirsiniz.

Birazcık bekledikten sonra, entity nesnemiz visual studio tarafından oluşturulmulş olacaktır. Artık tüm veritabanı işlemlerimizi bu entity üzerinden gerçekleştirebiliriz. Bizim konumuz tabiki bu işlemleri gerçekleştirmek değil, bu entity nesnesini kullanmak amacıyla örneklerken, sadece 1 kez örneklenmesini sağlamak...
İşte şimdi Singleton sınıfımızı yazmaya başlayacağız. Projemize DataAccess adında bir class ekleyelim ve ardından aşağıdaki kodları yazalım.
İşte bu kodlar bizim singleton desenimizi oluşturuyor. Kısaca kodları inceleyelim isterseniz. Öncelikle bizim DataContext' imizi bu sınıf içinde ele almamızı sağlayan static bir context nesnesi tanımlanmış. Ardından sınıfın singleton olmasında ki en önemli etken olan Constructor tanımlaması bulunuyor. Burada dikkat etmenizi istediğim şey constructor' ın public olarak değil de private olarak tanımlanmasıdır. Constructor 'ların ne zaman çalıştığını hatırlayalım.
using System;
namespace SingletonEF
{
public class DataAccess
{
private static DataContext context;
private DataAccess()
{
}
public static DataContext GetDataContext()
{
if (context == null)
{
context = new DataContext();
}
return context;
}
}
}
Object o = new Object();
Bir nesne new ile örneklendiği zaman ilk çalışan method yapıcı method olan constructor 'dır. Fakat biz nesnemizin sadece 1 kez oluşmasını istiyoruz. Böyle bir yapıda ben istediğim kadar nesne örnekleyebilirim. Ozaman benim önüne geçmem gereken nokta bu yapıyı değiştirmekte gizli. Bunu da constructor 'ı private tanımlayıp, dışarıdan erişimi engelleyerek yapabilirim. İsterseniz ufak bir deneme yapın ve constructor 'ı private tanımlanmış bir class 'ı dışarıdan new ile örneklemeye çalışın. Hata verdiğini sizde göreceksiniz.
Fakat benim bir şekilde bu nesneyi oluşturmam gerekiyor ki kullanabileyim. İşte yeni yapımızı oluşturacak olan son adımımızı da geriye DataContext döndüren bir static method ile yapıyoruz. Burada önemli olan methodun static olmasıdır. Hatırlayalım static methodları kullanmak için nesne örneklemeye gerek yoktu. Yani direk sınıf adı üzerinden ben bir static methoda erişebiliyorum. Bundan sonra bana kalan son şey ise, bu method içinde sadece 1 kez oluşmasını istediğim DataContext' in, daha önceden oluşup oluşmadığını kontrol etmek okadar. Bunu da eğer daha önceden oluşmadıysa yeni bir tane oluşturup, yok daha önceden oluştuysa da direk onu geri döndürerek yapıyorum. If koşulumuz da bu yapıyı sağlamış oluyor yani...
ÖNEMLİ : Aslında burada şunu söylemekte fayda var. Bu örnekte singleton olan sınıf DataContext değil, DataAccess adında bizim yazdığımız sınıftır. İstersek DataContext' ide constructor 'ını private yapıp, içine bir static Get.. methodu ekleyerek singleton hale getirebiliriz ki bunu da birazdan yapacağız zaten.
Şimdi bu DataAccess sınıfı yardımıyla, bu yapının nasıl kullanıldığını ve gerçekten sadece 1 tanemi nesne örnekleniyor görmek amacıyla ufak bir örnek yapalım. Bunun için main methodu içine aşağıdaki kodu yazıp, debug etmek yeterli...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SingletonEF
{
class Program
{
static void Main(string[] args)
{
DataContext context = DataAccess.GetDataContext();
DataContext context2 = DataAccess.GetDataContext();
DataContext context3 = DataAccess.GetDataContext();
var productList = (from product in context.Product
select product).Take(10);
foreach (Product p in productList)
{
Console.WriteLine(p.Name);
}
}
}
}
Dikkat ederseniz, context, context2 ve context3 adında 3 farklı context oluşturuyorum. Fakat ilk oluşturulan dışında hiç bir context nesnesi için yeni bir DataContext nesnesi örneklenmiyor. Uygulama çalıştığı sürece binlerce bile istek olsa sadece ve sadece 1 tane DataContext nesnesi kullanılıyor olacak...
Debug sonucunu aşağıda görebilirsiniz.
1. İstek


Görüldüğü gibi nesne daha önceden olmadığı için 1 kez oluşturuluyor.
2. İstek


Bu istek ve sonraki diğer tüm isteklerde yeni bir nesne oluşturmak yerine var olan context geri dönecektir...
Yukarıda ÖNEMLi notu ile belirttiğim ifade de söylediğim gibi burada singleton olan sınıf aslında DataAccess 'tir. Fakat biz aslında DataContext' in singleton olmasını istiyoruz. Dikkatli arkadaşlarımız kod bu haldeyken şöyle bir tanımlama yaparlarsa yeni bir DataContext oluştuğunu çok net görebilirler.
DataContext dc = new DataContext();
Peki bu durumun önüne nasıl geçeriz. Yapmamız gereken tek şey Entity framework 'ün oluşturduğu kodları singleton olacak şekilde revize etmek okadar. Biz artık bir sınıfı nasıl singleton yapacağımızı biliyoruz. O halde, EntityModel. Designer.cs isimli kod dosyasını açalım ve static bir DataContext değişkeni tanımlayıp, tüm constructorları private yapalım. Sonra geriye DataContext döndüren static bir method yazalım...
Önce static bir DataContext tanımlayalım.
private static DataContext dataContext;
Ardından 3 farklı constructor olduğu için her birini private yapalım.
private DataContext() :
base("name=DataContext", "DataContext")
{
this.OnContextCreated();
}
private DataContext(string connectionString) :
base(connectionString, "DataContext")
{
this.OnContextCreated();
}
private DataContext(global::System.Data.EntityClient.EntityConnection connection) :
base(connection, "DataContext")
{
this.OnContextCreated();
}
Ardından static methodumuzu yazalım ki, nesnemizi oluşturabilelim.
public static DataContext GetDataContext()
{
if (dataContext == null)
{
dataContext = new DataContext();
}
return dataContext;
}
Bu işlemlerden sonra artık DataAccess sınıfına pek ihtiyacımız kalmadı aslında.
Şöyle ki; eskiden DataAccess üzderinden eriştiğimiz context 'e, artık singleton olduğu için direk kendi üzerinden de gönül rahatlığı ile erişebiliriz.
DataContext context = DataContext.GetDataContext();
Artık aşağıdaki gibi bir kullanımın da önüne geçmiş bulunuyoruz. Yani saf singleton bir DataContext' imiz var artık.
DataContext dc = new DataContext();
Debug sonrası karşılaşacağınız durum ise aynıdır.
Açıkçası araya DataAccess gibi bir katman koymak şimdilik çok ta önemli değil. Fakat gerçek uygulamalarda genellikle veri kaynağı tek bir veritabanından ibaret olmaz. Veribanı dışında size veri sunan bir çok kaynak olabilir. Nitekim web servisleri bunun en güzel örnektir.Bunun dışından birden fazla entity ile çalışıyor da olabilirsiniz. İşte bu kadar fazla veri kaynağını tek bir merkezden (DataAccess sınıfı gibi) yönetmek çok daha mantıklı bir çözümdür.(Farklı mimarilerde uygulunabilir) Bende, araya farklı katmanlar ekleyebileceğiniz gibi bunları da singleton yapabileceğinizi göstermek için yazıyı bu şekilde ele almak istedim.
Konuyu kısaca özetlersek artık büyük boyuttaki entity objelerimizi singleton yaparak ram israfını önlemiş bulunuyoruz. Bunun dışında birde ipucu vermek gerekirse, eğer bu nesneyi önbellekte yedekler isek çok daha fazla performans kazancı elde ederiz...
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Data Access Layer,
Entity Framework,
Makale,
Object Oriented
10 Eylül 2009
Dependency Inversion Principle

Bu prensipte anlatılmak istenen şeyi Türkçe' ye çevirince ortaya, bağımlılıkların tersine çevrilmesi gibi anlaşılması zor olan bir şey çıkıyor. Fakat şimdilik bunun böyle isimlendirildiğini bilmeniz yeterli. Biz hemen konuyu daha net anlaşılması için açalım.
Öncelikle bu prensibin dayandığı ana fikri söylemekte fayda var. Şöyle ki; herhangi bir sınıf ile herhangi bir başka sınıf arasında, doğrudan doğruya bir bağın olması sakıncalıdır. Bu durum genelde bir sınıf, diğer bir sınıfı kendi içinde örnekliyorsa ortaya çıkar. Böyle bir durumda, kendi bünyesinde başka bir sınıf örnekleyen sınıfa üst sınıf, örneklenen sınıfada alt sınıf adının verelim. Şimdi demek istediğimizi şöyle basit bir şekilde örnekleyelim; üst sınıf, herhangi bir methodunda, alt sınıfı parametre olarak almamalıdır. Veya üst sınıf, alt sınıf tipinden bir property 'e sahip olmamalıdır. Ve bunlar gibi bağımlılığa neden olacak kullanım şekillerini örnek verebiliriz...
Peki böyle bir durum yaratmadan nasıl sınıf hiyeraşimizi kurabiliriz. Çözüm; üst sınıf ile alt sınıf arasına, soyut bir katman koymak ile çözülebilir. Diğer bir deyişle, alt sınıflar ortak bir Interface 'den veya Abstract bir sınıftan türetilip, üst sınıfın da bu Interface 'e veya Abstact Class 'a bağımlı olması sağlanabilir.
Aşağıda yanlış ve doğru tasarım şekillerini görebilirsiniz.
Aslında yapılmak istenen şey tamamen şudur; öyle bir yapı olmaldır ki, üst sınıf ilerde sisteme eklenebilecek yeni tüm alt sınıfları kullanabilsin. Burada yapılan işlemde tamamen budur. Böylece üst sınıfın kullanmasını istediğimiz yeni bir sınıf eklemek istediğimiz zaman tek yapmamız gereken şey, alt sınıfı bu soyut katmandan türetmek okadar.
Şimdi bu örneği birde koda dökelim isterseniz. Örnek senaryoda üst ve alt sınıf mantığının anlaşılmasını kolaylaştırmak için alt sınıf olarak bir Worker sınıfı olacak ve üst sınıf olarak ta bir Manager sınıfımız olacak.
Önce kötü tasarıma bir bakalım.
public class Worker
{
public void Work()
{
Console.WriteLine("Calisiyorum...");
}
}
public class Manager
{
Worker worker;
public void SetWorker(Worker w)
{
worker = w;
}
public void Manage()
{
worker.Work();
}
}
Kodda gördüğünüz gibi Manager sınıfı direk olarak Worker tipini kullandığı için Manager sınıfı, Worker sınıfına direk olarak bağımlıdır. Bu durumun zorluğunu görmek için kendimize şu soruyyu soralım, "biz bu Manager sınıfının, SuperWorker adında yeni bir sınıf ile de çalışmasını istersek ne yapacağız ?" Yanlış çözümlerden birine örnek verecek olursak, önce SuperWorker 'ı tanımlarız. Daha sonra bunu kullanacak Manager sınıfı içindeki methodları SuperWorker' a özel olarak yazarız. Yani aşağıdaki gibi.
public class Worker
{
public void Work()
{
Console.WriteLine("Calisiyorum...");
}
}
public class SuperWorker
{
public void Work()
{
Console.WriteLine("Daha cok calisiyorum");
}
}
public class Manager
{
Worker worker;
public void SetWorker(Worker w)
{
worker = w;
}
public void Manage()
{
worker.Work();
}
SuperWorker superWorker;
public void SetSuperWorker(SuperWorker s)
{
superWorker = s;
}
public void ManageSuperWorker()
{
superWorker.Work();
}
}
Bu yapıyıda aslında bir tip kontrolü sayesinde Manage methodu içinde, bir if blogu ile kontrol edebiliriz. Yada Manage methodunu overload ederiz. Veya bir çok farklı senaryo ile destekleyebiliriz. Fakat sorun bu şekilde çözülmeye çalışıldığı her denemede, değişiklik yapılacak yer Manager sınıfıdır. Başka ihtimaliniz yok. Çünkü bu sınıflara bağımlısınız. Oysa DIP' in sağlamak istediği doğru tasarım bunun tam tersi olmakla beraber, şudur; üst sınıf içinde hiçbir değişiklik yapmadan, genişletilebilir bir yapıyı geliştirebilmektir. Ozaman çözüm yolu aşağıdaki gibi olacaktır. Yani alt sınıfları ortak bir interface olan IWorker 'ı uygulayarak geliştirmek. Sonrasında da manager sınıfını bu interface ile bağımlı hale getirmek.
public interface IWorker
{
void Work();
}
public class Worker : IWorker
{
public void Work()
{
Console.WriteLine("Calisiyorum...");
}
}
public class SuperWorker : IWorker
{
public void Work()
{
Console.WriteLine("Daha cok calisiyorum...");
}
}
public class Manager
{
IWorker worker;
public void SetWorker(IWorker w)
{
worker = w;
}
public void Manage()
{
worker.Work();
}
}
Gördüğünüz gibi Manager sınıfı tamamen IWorker isimli interface ile bağımlıdır. Diğer bir deyişle, Manager sınıfı için önemli olan sadece IWorker interface'ini uygulamış bir şekilde gelen nesnelerdir. Worker veya SuperWorker olması onun için önemli değildir. Onları tanımaz bile. Bu şu demektir ki, Manager sınıfı IWorker' ı uygulayan bütün sınıflar ile çalışabilir. İşte extend edilebilir yani genişletilebilir kod yazmanın tekniklerinden biride budur.
Bu yazıyla birlikte Design Principles başlıklı yazı dizimin SOLID Principles bölümünü bitirmiş bulunuyorum. Sizde takdir edersiniz ki bu tarz fikirsel konuları anlatmak her zaman için bir teknolojinin nasıl kullanıldığını anlatmaktan daha zordur. Bende Türkçe kaynak sıkıntısı çektiğimiz bu alanda elimden geldiği kadar edindiğim bilgileri sizlerle paylaşmaya çalıştım...
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Desing Principle,
Makale,
SOLID
Interface Segregation Principle

Öncelikle bu prensibin dayandığı ana fikri genel çerçevede açıklamaya çalışıp, ardından bir önek üzerinden giderek yazımıza devam edelim...
Şimdi, elimizde ortak özellikler barındıran bir çok sınıf olduğunu düşünelim. Genelde böyle durumlarda bu sınıfları ortak olan tek bir interface 'i uygulayarak oluştururuz. Bu elbette ilk etapta mantıklı ve işimizi gören bir yaklaşımdır. Fakat bizim geliştirdiğimiz uygulama tabiki genişletilebilir bir yapıya sahip olacak ve ilerde uygulamamıza bu sınıflara benzer yeni sınıflar ekleme ihtiyacı duyacağız. Bunu yaparken tabiki ilk yapacağımız şey, bu yeni sınıfları da aynı interface' i uygulayarak yaratmak olacaktır. Fakat yeni sınıfımızın yapısı gereği, bu interface içinde bulunan bazı üyeleri kullanması doğru ve mantıklı değildir. İşte bizim sorunumuz da tam bu noktada ortaya çıkıyor. Sınıfların, interface içinde kullanmayacağı kesin olarak belli üyeler varsa ve bunlar sınıfın yapısına aykırı bir durum oluşturuyorsa, sınıfın bu interface 'i uygulaması doğru değildir.
Çözüm ilk etapta yeni bir interface yaratıp, yeni sınıfa onu uygulamak gibi görünse de bu durum da pek sağlıklı değildir. Çünkü ilerde bu tarz sınıfların sayısının arttığı bir durumda, sınıf hiyerarşisi içinden çıkılamayacak kadar karışık bir hal almaya başlar. Bunu da kimse istemez herhalde. Peki ozaman ne yapacağız? Çözüm okadar da zor değil aslında. Tek yapmamız gereken şey, interface leri oluştururken barındırdığı üyeleri ortak olacak şekilde parçalayıp, bu üyeleri farklı interface 'ler altında toplayıp, ayrı ayrı interface' ler oluşturmak okadar.
Bu genel açıklamadan sonra şimdi somut bir örnek ile ne demek istediğimizi çok daha net bir şekilde örnekleyelim. Kullanacağım örnek genelde bu prensibin anlatılırken kullanıldığı bir senaryoya sahip. Bende bu örneğin, sorunu ve çözümünü çok güzel açıkladığını düşündüğüm için aynen kullanacağım.
Örneğimiz de işçilerin ortak özelliklerini barındıran IWorker adından bir interface mevcut. Bu interface içinde işçilerin çalışma yeteneğini gösteren Work adında bir method ve yemek yeme yeteneğini gösteren Eat adında bir method var. Bunun dışında bu interface ' i uygulayan normal bir çalışan olan Worker ve daha çok çalışan SuperWorker adında 2 tane işçi sınıfı var. Bütün işçi tipleri de bu interface 'i uygulayarak yaratılıyor. Yani biz yeni bir işçi sınıfı tanımlamak istersek bunu da IWorker interface' ini uygulayarak yaparız. Böylece bizim bütün işçilerimiz hem çalışıp hem de yemek yiyebilme yeteneklerine sahip olmuş oluyor. Son olarak birde Manager adında, işçilerin ne yapmasını gerektiğini söyleyenbir sınıf mevcut.
public interface IWorker
{
void Work();
void Eat();
}
public class Worker : IWorker
{
public void Work()
{
Console.WriteLine("Az is yapar");
}
public void Eat()
{
Console.WriteLine("Az yemek yer");
}
}
public class SuperWorker : IWorker
{
public void Work()
{
Console.WriteLine("Cok is yapar");
}
public void Eat()
{
Console.WriteLine("Cok yemek yer");
}
}
public class Manager
{
IWorker worker;
public void SetWorker(IWorker w)
{
worker = w;
}
public void Manage()
{
worker.Work();
}
}
Buraya kadar herşey çok güzel ve sorunsuz görünüyor. Şimdi size herşeyin açıklanmasına neden olacak soruyu sormak istiyorum. Uygulamayı geliştirdiğiniz fabrika, insan işçilerin yanına bir de robot işçiler almaya karar verdi ! Robot olmasına rağmen sonuçta o da bir işçidir. Bu durumda robot sınıfının mutlaka IWorker interface' ini uygulaması gerekiyor. Fakat robotlar yemek yemez. Biz bu örnekte sadece yemek yeme olayı üzerinden gittik. Fakat bu kompleks bir sınıf olsaydı, robot yapısına aykırı bir çok olay olacaktı.Örneğin maaş gibi veya izin kullanma hakkı gibi.Bu örnekler çoğaltılabilir. Hal böyleyken bu kadar farklı yeteneklere sahip yeni bir robot sınıfının, bu özellikleri bünyesinde barındırması onu robot olmaktan çıkarır aslında. Bu da asla doğru bir tasarım şekli değildir.
Çözüm yukarda da dediğimiz gibi temel interface ' i parçalayıp, çalışabilen ve yemek yiyebilen gibi 2 farklı interface yaratmak. Sonra eklenecek olan işçi sınıflarına bu interfaceler 'den uygun olanlarını seçip, onları uygulamak. Kodun revize edilmiş hali aşağıdaki gibidir.
public interface IWorkable
{
void Work();
}
public interface IFeedable
{
void Eat();
}
public class Worker : IWorkable, IFeedable
{
public void Work()
{
Console.WriteLine("Az is yapar");
}
public void Eat()
{
Console.WriteLine("Az yemek yer");
}
}
public class SuperWorker : IWorkable, IFeedable
{
public void Work()
{
Console.WriteLine("Cok is yapar");
}
public void Eat()
{
Console.WriteLine("Cok yemek yer");
}
}
public class Robot : IWorkable
{
public void Work()
{
Console.WriteLine("Cok fazla is yapar, yemek yemez");
}
}
public class Manager
{
IWorkable worker;
public void SetWorker(IWorkable w)
{
worker = w;
}
public void Manage()
{
worker.Work();
}
}
Interface 'lerin parçalanıp ayrı ayrı ele alınması gerektiğini söyleyen tasarım prensibimiz işte bu kadar arkadaşlar. Aslında şunu söylmekte fayda var diye düşünüyorum. Diğer tüm prensiplerde olduğu gibi bu prensipte de, zor olan şey; prensiplere uygun bir şekilde kod yazmak değil, prensiplere aykırı olan durumları tespit etmektir. Bu da aslında öyle çok zor bir şey değil ve zamanla aşılabilecek bir durumdur. Bu tarz tasarımsal problemler ile karşılaştıkça ve buna kafa yordukça, herhangi bir sınıf hiyerarşisine veya koda şöyle bir bakınca, bir çok eksikliğini ve güzelliğini görebilecek duruma geliyorsunuz zaten.
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Desing Principle,
Makale,
SOLID
09 Eylül 2009
Liskov' s Substitution Principle

Bu prensibin kuralı; türeyen sınıfların üyeleri, temel sınıfın üyeleri ile tamamen yer değiştirebilir ilkesine dayanır.
Bu dediğimizi bir örnek üzerinde görmek herşeyin daha net anlaşılmasını sağlar elbette. Ozaman hemen örneğimize geçelim.
Elimizde Rectangle adında bir sınıf olsun. Bu sınıf, Width ve Height adında iki tane özellik barındırsın ve bu özelliklerin çarpımını hesaplayıp geri döndüren GetArea adında bir method barındırsın. Bu methodun görevi sadece alan hesabı yapmak okadar. Birde bu sınıftan türeyen Square adında bir sınıf olsun.
public class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
public int GetArea()
{
return Width * Height;
}
}
public class Square : Rectangle
{
private int width;
public int Width
{
get { return width; }
set
{
width = value;
height = value;
}
}
private int height;
public int Height
{
get { return height; }
set
{
height = value;
width = value;
}
}
}
Şimdi yukarıdaki kodlarda bulunan, Square sınıfı içindeki özelliklerin set bloklarına dikkat etmenizi istiyorum. Gördüğünüz gibi Width veya Height özelliklerinden herhangi birine bir değer atadığınız zaman diğerinede aynı değer atanıyor. Bunu neden yaptık derseniz, bir karenin 4 kenar uzunluğuda birbirine eşit olmalıdır diyebiliriz. Böylece bu sınıfı kullanıp bu özelliklere değer atarken olası bir yanlış hesabın önüne geçmiş oluyoruz...
Sınıflarımızı yazdıktan sonra test kodlarımızı yazmaya geçebiliriz. Şimdi sizden şöyle düşünmenizi istiyorum. Biz bu sınıfları kullanmak istediğimizde, direk bir nesne oluşturma işlemi yapmayalım da, gerekli işlemleri yapan bir factory sınıfımız olduğunu varsayalım. Bu factory sınıfının içinde de GetRectangle adında geriye Rectangle sınıfının referansını döndüren bir method olsun. Şu durumda Factory' nin nasıl çalıştığı ve methodun içeriği çokta önemli değil. Şimdilik önemli olan sadece, geriye bir Rectangle referansı döndüren method imzasına sahip bir method olması. Fakat koda dikkat ederseniz geriye dönen sınıf Rectangle tipinde değil de, Square tipindendir. Yani aşağıdaki gibi;
public static class Factory
{
public static Rectangle GetRectangle()
{
// ...
return new Square();
}
}
Şimdi bu factory sınıfmızı kullanarak örneğimizi test edelim.
class Program
{
static void Main(string[] args)
{
Rectangle rect = Factory.GetRectangle();
rect.Width = 5;
rect.Height = 10;
Console.WriteLine(rect.GetArea());
}
}
Şimdi herşeyden önce programı çalıştırıp çıktıya bakarsanız eğer, ekrana 50 yazdığını görürsünüz. Fakat 100 olması gerekmiyor mu sizce de ? Çünkü az önce Square sınıfı içinde özelliklere değer atanırken, en son atanan değerin diğer özelliğe de atandığını söylemiştim. O zaman burada Height özelliğine atadığım değerin, otomatik olarak Width özelliğine de atanması gerekmiyor mu ? Eğer böyle olsaydı 10*10 = 100 sonucuna ulaşmam gerekirdi. İşte işin püf noktasıda tam olarak burası. Eğer bunu gördüyseniz olayı biraz kavramış olmanız gerekiyor. Şimdi işin ispatına geçelim.
Rectangle rect = Factory.GetRectangle();
Bu satıra dikkat ederseniz eğer, ben rect adında bir Rectangle nesnesi örnekliyorum. GetRectangle 'ın method imzasına göre geriye bir Rectangle döndürdürmesi gerekse bile, bu method kendi içinde aslında geriye bir Square tipi döndürüyor. Fakat oluşan nesne bir Rectangle referansına atandığına göre bir Rectangle olması gerekmiyor mu ? Hayır tabiki de, çünkü zaten Square sınıfı, Rectangle sınıfından türediği için her Square aslında bir Rectangle 'dır. Fakat burada önemli olan şey, Square sınıfının kendi içinde tanımlanan özelliklere göre değilde, türediği sınıf olan Rectangle 'ın özelliklerine göre davranıyor olması. Liskov 'un prensibi de şunu söyler zaten; türeyen sınıfın özellikleri, temel sınıfın özellikleri ile yer değiştirebilir.
Şimdi programı debug edip, Quick Watch' tan rect nesnesinin gerçek tipinin ne olduğunu ve hangi özelliklerine hangi değerlerin atandığına bakalım.

Resimden de anlaşılan şu ki, Square nesnesi Width ile Height değerlerini Rectangle içindeki özelliklere atamış. Bu durumda bizim Square sınıfı için yazdığımız Width ve Height özelliklerinin birbirlerine eşit olması gerektiğini belirtken kısıt ihlal edilmiş oluyor. Bu durumdan kurtulmanın yolu ise, Square sınıfını Rectangle' dan bağımsız bir şekilde tanımlamaktır.
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Desing Principle,
Makale,
SOLID
08 Eylül 2009
Open Closed Principle

Bu prensibin ana fikri; geliştirilecek olan uygulamanın genişlemelere açık fakat modifikasyonlara kapalı olması gerektiğidir. Diğer bir deyişle var olan uygulama üzerine sürekli yeni modüller ve işlevler ekleyebilmelisiniz. Fakat bunu yaparken var olan kodlar üzerinde asla bir değişiklik yapmamalısınız.
Bu prensibe olan ihtiyaç, genelde bir yönetici sınıfın, yönettiği diğer sınıflar ile iletişim kurduğu durumlarda ortaya çıkıyor. Şöyle ki; bizim elimizde GraphicEditor adında bir yönetici sınıf olsun. Bu sınıf ekrana çeşitli şekillerin çizilmesinden sorumlu olsun ve yapısı aşağıdaki şekildeki gibi olsun.

public class GraphicEditor
{
public void DrawShape(Shape s)
{
if (s._type == 1)
{
DrawRectangle((Rectangle)s);
}
else if (s._type == 2)
{
DrawCircle((Circle)s);
}
}
public void DrawRectangle(Rectangle s)
{
Console.WriteLine("Rectangle");
}
public void DrawCircle(Circle s)
{
Console.WriteLine("Circle");
}
}
Şekilden ve kodlardan da görüldüğü gibi her bir şekilde direk olarak yönetici sınıf olan GraphicEditor sınıfına bağlı. İşte bu durum Robert Martin' in belirlediği kötü tasarım ilkelerinden her üçünede aykırı.
Öncelikle bu kadar birbirine bağlı sınıflardan esnek davranmalarını beklemek pek mümkün değil. Bu durum da Rigidity ilkesine tamamen aykırı. If koşulu ile hangi şeklin çizileceğinin belirlenmesine değinmiyorum bile.
Bunun dışında sisteme eklemeye çalışacağım herhangi bir yeni şekil, sistemin bir çok yerinde değişikliğe neden olacaktır. Kompleks yapılarda iş akışı hataları ve exceptionların çıkması muhtemel. Bu durum da Fragility 'e aykırıdır.
Son olarak bu kadar birbirine bağımlı bir mimaride siz kalkıp GraphicEditor sınıfını Shape, Circle ve Rectangle sınıfları olmadan tek başına bir yere taşıyamayamazsınız. Çünkü bu sınıflara doğrudan bir bağımlılığı vardır. Bu durumda Immobility ilkesine ters düşer.
Peki çözüm nedir diye sorarsanız, devam edelim...
Böyle bir durumdan kurtulmak için tek yapmamız gereken şey; şekilleri ortak bir abstract sınıftan türetip, bu ortak sınıf içine yazacağımız abstract bir method ile Draw işlemini her sınıfın kendine has bir şekilde ele almasını sağlamamız okadar. Bunuda tabiki Draw methodunu her sınıf kendi içinde override edecek şekilde geliştirerek yababiliriz. Doğru tasarımın diagramı ve kodları aşağıdaki gibidir.

public abstract class Shape
{
public abstract void Draw();
}
public class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("Rectangle");
}
}
public class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Circle");
}
}
public class GraphicEditor
{
public void DrawShape(Shape s)
{
s.Draw();
}
}
Bu yapıyı bir örnekte kullanmaya başladığımız zaman, polymorphism 'in en güzel halini aşağıdaki gibi görebiliyoruz.
Hiç bir koşula bakılmadan, benim gönderdiğim türe uygun bir çizim işlemi gerçekleşmiş oluyor. Artık uygulamaya yeni bir şekil eklemek istersem tek yapmam gereken onu Shape isimli asbstract sınıftan türetmek ve Draw methodunu override etmek okadar.
class Program
{
static void Main(string[] args)
{
GraphicEditor editor = new GraphicEditor();
Rectangle r = new Rectangle();
editor.DrawShape(r);
Circle c = new Circle();
editor.DrawShape(c);
}
}
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Desing Principle,
Makale,
SOLID
Single Responsibility Principle

Bir class ’ın sadece ve sadece bir tek sorumluluğa sahip olması gerektiğidir. Buradan yola çıkarak şunu diyebiliriz ki; bir class ‘ın ileride herhangi bir değişikliğe uğraması için öne sürülebilecek sadece bir tane sebep olmalıdır.
Diğer bir deyişle, bir class ‘a verilebilecek görev tekil olmalıdır. Örnek vermek gerekirse; bir sınıf, temel kayıt işlemlerinden (CRUD) sorumluyken aynı zamanda bir raporlama işlemini de yerine getirecek işlevleri yönetmemelidir. Veya rapor almaktan sorumlu bir sınıf aynı zamanda bu raporları ilgili kişilere mail atabilecek yeteneğe sahip olmamalıdır. Kısaca her sınıf, bir tek amaca hizmet edecek şekilde geliştirilmelidir.
Bunun dışında tek bir amaca hizmet edecek olan sınıflarında, kendi içinde ileride çıkabilecek değişiklik sebepleri de tekil olmalıdır.
Dilerseniz bu söylediklerimi daha rahat anlayabilmek aşağıdaki örneği inceleyelim. Elimizde mesaj göndermekten sorumlu, IMessageManager interface ‘ini implemente etmiş MessageManager adında bir sınıf var.
Public Interface IMessageManager
{
void Send(string message, string number);
}
Public Class MessageManager : IMessageManager
{
void Send(string message, string number)
{
// Send…
}
}
Koda ilk baktığımızda herşey son derece düzgün görünüyor. Send adında iki parametre alan bir method var. Bu method aldığı string tipindeki mesajı, ikinci parametrede aldığı numaraya gönderiyor. Fakat sorun tamda bu noktada başlıyor. Siz programı bu şekilde piyasaya sürdünüz diyelim. 3 ay sonra MMS diye bir teknoloji çıktığı zaman, sizin string tipinde parametre alan methodunuz bu ihtiyacı karşılamayacak. Tamam programı yayınlandığınız zaman böyle bir teknoloji yoktu. Zaten beklenti asla MMS diye bir teknolojiyi önceden tahmin edip ona göre bir sınıf tasarlamanız değildir. Fakat beklenen şey; ileride değişiklik olabileceğini tahmin etmeniz ve buna uygun esnek bir yapı tasarlamanızdır. Tabi olası bu yeniliklere mümkün olduğu kadar modüler çözümler sunmak gerekiyor. Şöyleki; bu şekilde yazılan bir kodun yeni bir MMS teknolojisine sunacağı çözüm, ancak MMS tipinde parametre alan ikinci bir Send methodu yazmaktan geçer. Diğer bir deyişle Send methodunu overload etmekten geçer. Bu da benim mesaj göndermekten sorumlu olan MessageManager isimli sınıfımın, mesaj göndermek ile tamamen alakasız olarak, bir mesaj tipi yüzünden değişime uğraması demektir. Bu da SIR’ a tamamen aykırı bir durumdur. Benzer şekilde 5 ay sonra da sesli mesaj teknolojisi çıktığı zaman aynı süreci malesef tekrar yaşamak gerekecektir…
Çözüm son derece basittir. Mesajımızı string olarak göndermek yerine, IMessage gibi bir Interface ‘ten implemente edilmiş bir sınıf tipinde göndermek işimizi görecektir.
Methodumuz artık IMessage referansına sahip bir parametre almaktadır. Yani aşağıdaki kodda görüldüğü gibi.
Public Interface IMessage
{
}
Public Class SMS : IMessage
{
public string Message;
}
Public Class Picture
{
public String Name;
public int Size;
}
Public Class MMS : IMessage
{
public Picture Message;
}
Public Interface IMessageManager
{
void Send(IMessage message, string number);
}
Public Class MessageManager : IMessageManager
{
void Send(IMessage message, string number)
{
// Send…
}
}
Artık elimizde bir IMessage Interface’ i var ve bunu implemente etmiş, SMS ve MMS sınıfları vardır. SMS’ in sadece string bir mesajı vardır, fakat MMS’ in Picture tipinde çok farklı bir mesajı vardır. Mesaj tipleri farklı dahi olsa biz bu kodu artık şu şekilde kullanabiliriz.
SMS sms = new SMS();
sms.Message = “mesaj”;
MessageManager manager = new MessageManager();
manager.Send(sms, “123”);
//----------------------------------
Picture pic = new Picture();
pic.Name = “resim”;
pic.Size = 130;
MMS mms = new MMS();
mms.Message = pic;
manager.Send(mms,”123”);
Görüldüğü gibi ben MessageManager sınıfında en ufak bir değişiklik bile yapmadan MMS gibi farklı bir teknolojiyi desteklemiş oldum. Bunu da sadece yeni sınıflar ekleyerek yaptım. İşte modüler tasarım dediğimiz şey özünde böyle bir mimariye sahip olmalıdır.
SIR, modüler programlamanın temelinde yatan prensiplerden belkide en önemlisidir. Bu şekilde geliştirilen sınıfların birbirlerine olan bağımlılıkları son derece düşüktür. Bu da modüler programlamanın en önemli gereksinimidir. Zaten ileride göreceğimiz diğer prensiplerinde dayandığı en önemli amaç, sınıfları mümkün olduğu kadar birbirinden soyutlamak ve bağımsız tutmaktır.
Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com
Etiketler:
Desing Principle,
Makale,
SOLID
Principles of Class Design
Design Principles kavramı, kötü tasarımlardan uzak durmak için belirlenmiş belli kurallardan oluşan bir kurallar zinciridir.
Principles of Class Design kavramı ise sınıflar üzerindeki modellemede uymamız gereken prensipleri belirlemiştir. Bunun dışında ayrıca paketlerin nasıl tasarlanması gerektiğini belirten prensiplerde vardır. Biz bu yazı dizimizde sınıflar için belirlenmiş prensipleri tanıyacağız.
Sınıflar için uyulması gereken bu prensipler kötü tasarıma neden olabilecek 3 ana unsuru ortadan kaldırmak amacıyla geliştirilmiştir. Peki nedir bu kötü tasarımın oluşmasına neden olabilecek 3 unsur. Robert Martin bunları şöyle sıralamıştır;
Rigidity (Esnemezlik) : Kullanılan tasarımın esnek olmadığını gösterir. Yani kullanılan tasarımın geliştirmeye ve plug-in mimarisine uygun olmadığını gösterir.
Fragility (Kırılganlık) : Sistemin bir yerinde yaptığınız bir değişikliğin, sistemin bir başka yerinde sorun çıkarmasıdır.
Immobility (Sabitlik) : Geliştirdiğiniz bir modülün tekrar kullanılabilir olmadığını gösterir.
Bu 3 ana unsurun aslında ortak bir paydada buluştuğunu ve buna çözüm bulmak için prensipler geliştirildiğini söyleyebiliriz. Şöyle ki; bu durumların her birinin ortaya çıktığı nokta bağımlılık seviyesi çok yüksek sınıflarda görülür. Sınıf tasarımları eğer birbirlerine sıkı sıkıya bağlı ise, bu tasarım ne esnek, ne sağlam ne de taşınabilir olur. Buradan şunu söyleyebiliriz ki tüm prensiplerin çözüm ararken yapmaya çalıştığı şey, mümkün olduğu kadar sınıfların birbirlerine olan bağımlılıklarını azaltmaktır. Bunları nasıl yapılacağını tek tek göreceğiz zaten. Fakat bundan önce şimdi, dilerseniz bu sorunları ortadan kaldırmak için uymamız gereken prensiplere çok kısa bir şekilde bakalım.
Single Responsibility Principle : Her modülün bir tek sorumluluğa sahip olmasını ve ilerde olası bir değişiklikğin de tek bir nedene dayandırılması gerektiğini belirtir.
Open/Closed Principle : Genişlemelere açık, modifikasyonlara kapalı bir tasarım kullanılması gerektiğini belirtir.
Liskov 's Substitution Principle : Türeyen sınıfın üyeleri, temel sınıfın üyeleri ile tamamen yer değiştirebilir olmalıdır.
Interface Segregation Principle : Interface' lerin mümkün olduğu kadar ayrıştırılması gerektiğini belirtir.
Dependency Inversion Principle : Yüksek seviye sınıfların, düşük seviye sınıflara direkt olarak bağımlı olmaması gerektiğini belirtir. Bunu da araya bir abstract sınıf veya Interface koyarak yaparız.
Principles of Class Design kavramı ise sınıflar üzerindeki modellemede uymamız gereken prensipleri belirlemiştir. Bunun dışında ayrıca paketlerin nasıl tasarlanması gerektiğini belirten prensiplerde vardır. Biz bu yazı dizimizde sınıflar için belirlenmiş prensipleri tanıyacağız.
Sınıflar için uyulması gereken bu prensipler kötü tasarıma neden olabilecek 3 ana unsuru ortadan kaldırmak amacıyla geliştirilmiştir. Peki nedir bu kötü tasarımın oluşmasına neden olabilecek 3 unsur. Robert Martin bunları şöyle sıralamıştır;
Rigidity (Esnemezlik) : Kullanılan tasarımın esnek olmadığını gösterir. Yani kullanılan tasarımın geliştirmeye ve plug-in mimarisine uygun olmadığını gösterir.
Fragility (Kırılganlık) : Sistemin bir yerinde yaptığınız bir değişikliğin, sistemin bir başka yerinde sorun çıkarmasıdır.
Immobility (Sabitlik) : Geliştirdiğiniz bir modülün tekrar kullanılabilir olmadığını gösterir.
Bu 3 ana unsurun aslında ortak bir paydada buluştuğunu ve buna çözüm bulmak için prensipler geliştirildiğini söyleyebiliriz. Şöyle ki; bu durumların her birinin ortaya çıktığı nokta bağımlılık seviyesi çok yüksek sınıflarda görülür. Sınıf tasarımları eğer birbirlerine sıkı sıkıya bağlı ise, bu tasarım ne esnek, ne sağlam ne de taşınabilir olur. Buradan şunu söyleyebiliriz ki tüm prensiplerin çözüm ararken yapmaya çalıştığı şey, mümkün olduğu kadar sınıfların birbirlerine olan bağımlılıklarını azaltmaktır. Bunları nasıl yapılacağını tek tek göreceğiz zaten. Fakat bundan önce şimdi, dilerseniz bu sorunları ortadan kaldırmak için uymamız gereken prensiplere çok kısa bir şekilde bakalım.
Single Responsibility Principle : Her modülün bir tek sorumluluğa sahip olmasını ve ilerde olası bir değişiklikğin de tek bir nedene dayandırılması gerektiğini belirtir.
Open/Closed Principle : Genişlemelere açık, modifikasyonlara kapalı bir tasarım kullanılması gerektiğini belirtir.
Liskov 's Substitution Principle : Türeyen sınıfın üyeleri, temel sınıfın üyeleri ile tamamen yer değiştirebilir olmalıdır.
Interface Segregation Principle : Interface' lerin mümkün olduğu kadar ayrıştırılması gerektiğini belirtir.
Dependency Inversion Principle : Yüksek seviye sınıfların, düşük seviye sınıflara direkt olarak bağımlı olmaması gerektiğini belirtir. Bunu da araya bir abstract sınıf veya Interface koyarak yaparız.
Etiketler:
Desing Principle,
Makale,
SOLID

