Command-Query Separation Principle

Nesneye yönelik programlamanın önemli prensiplerinden olan Command Query Seperation Prensibini küçük bir örnekle inceleyeceğiz.Bu konuda yine örnekleri gerçek dünyadan olsun diye eski kodlarımı baya bir karıştırdım. Eski kodlarda her türlü bad smell bulabiliyorum ne mutlu bana :) Öncelikle bu prensibi ihlal eden aşağıdaki kodumuza bakalım.Bunu C# da Property olarak yazmışım. Java içinde aynı kodu getter olarak yazabiliriz. İki koduda aşağıda görüyorsunuz.

C# Versiyonu

<br />
public Resim KapakResim<br />
{<br />
 get<br />
  {<br />
  if(kapakResim!=null)<br />
   return kapakResim;<br />
  else<br />
  {<br />
   bosResim.KayitYolu =bosResim.ServerDizini &quot;yok.gif&quot;;<br />
   bosResim.Kaydet();</p>
<p>   return null;<br />
  }</p>
<p> }<br />
}<br />

Java Versiyonu

<br />
public Resim getKapakResim()<br />
 {<br />
 if (kapakResim != null)<br />
 return kapakResim;<br />
 else<br />
 {<br />
 bosResim.KayitYolu = bosResim.ServerDizini &quot;yok.gif&quot;;<br />
 bosResim.Kaydet();</p>
<p> return null;<br />
 }<br />
 }<br />

Şimdi yukarıdaki koda baktığınızda hiçbir problem görmüyor olabilirsiniz. İlk başlarda bende görmüyorum :) Buradaki problem şöyle açıklayalım. Dışarıdan birisi sizin yukarıdaki gibi yazdığınız kodu alıp kullandığında masum bir fikirle aşağıdaki gibi kodunun içinde kullanacak

  • C# da Resim resim =resimlistes.KapakResim
  • Java da Resim resim=resimListesi.getKapakResim();

Sınıfı kullanan bunun basit bir get metodu olduğunu yani sadece bir nesneyi bize geri döndürdüğünü düşünüyor fakat arka planda boş resim oluşturup dosya olarak kayıt ettiğinden haberi yok.Yani kullanıcı sadece yan etkisiz bir nesne almayı beklerken bu getter metodları nesnenin iç yapısında değişiklikler yapıp çeşitli işlemler yapıyor. Yani kodun anlaşılabilirliği oldukça düşük. Çünkü siz getKapakResim dediğinizde içeride boş resim oluşturup kayıt ettinden haberiniz olmuyor. Buda hata yapmaya oldukça açık bir yapı.

Bu yüzden ilk olarak bu prensibi Bertrand Meyer ortaya atıyor.Ne demiş şöyle özetleyelim. Nesnelere ait metodlar anlaşılabilir bir kod yapısı için şu şekilde olmalıdır.

  • Query Metod : Nesnenin içinde hiçbir değişiklik yapmadan hiç bir yan etkisi olmadan sadece geri dönüş tipinde bir nesne geri döndürür.(nesne.getResim(),nesne.Resim….gibi)
  • Command Metod : Nesnenin içinde çeşitli işlemler yapan durumunu değiştiren genelde dönüş tipi void olan metodlardır. (nesne.kaydet(),nesne.yap()…gibi)

Şimdi yukarıdaki koda baktığımızda problemi casino

online daha iyi görebiliyoruz.Bu kodda nesne.KapakResim yada nesne.getKapakResim() çağırıldığında hem nesnenin durumunda değişiklikler yapılıyor hemde geri bir nesne dönülüyor. Yani Command ve Query aynı metod içinde yapılmış. Bu metodu aşağıdaki aşağıdaki gibi Command ve Query olarak ikiye ayırırsak kodun anlaşılabilirliği daha da artacaktır.

<br />
 public Resim getKapakResim()<br />
 {<br />
 return kapakResim;<br />
 }</p>
<p> public void bosResimKaydet()<br />
 {<br />
 bosResim.KayitYolu = bosResim.ServerDizini &quot;yok.gif&quot;;<br />
 bosResim.Kaydet();<br />
 }<br />

Yukarıdaki gibi kodumuzu ikiye ayırdık.Yani Query metodu getKapakResim sadece hiçbirşey yapmadan geri resim döndürüyor. Diğer Command metodu olan bosResimKaydet metodu ise nesnenin içinde çeşitli işlemler yapıyor. Tabi üstteki if kontrolü nereye gitti diyebilirsiniz. Dışarıda kodu kullanan da şu şekilde kodu kullanıyor.

<br />
 public void arabaKaydet()<br />
 {<br />
 if (resimListesi.KapakResim == null)<br />
 resimListesi.bosResimKaydet();<br />
 else<br />
 Resim kapakResim = resimListesi.gerKapakResim();<br />
 }<br />

Kısaca özetlersek bu prensibe uymanız kodunuzun hata oranını azaltacak anlaşılabilirliğini oldukça arttıracaktır. Tabi herzaman mutlaka uyacaksınız diye bir şey yok ama çoğu durumda metodları Command ve Query olarak ayırmak oldukça faydalı..Prensiplere uyalım uymayanları uyaralım :)

3 thoughts on “Command-Query Separation Principle

  1. Tolga Yaramis

    Tekrar eline saglik güzel makale olmus Cihan. Daha önce refactoring bölümünde nesnelerin ve methodlarin isimlendirilmesi ile ilgili bir makaleni okumustum. Burda arabaKaydet() methoduna baktigimda bir kaydetme islemi yapiyor ama resim listesi ile ilgii birsey kaydediyor gibi ve kapak resim de bos degilse kaydetme islemi yapmayip get islemi yapiyor. burayada bir refactoring gerekir gibi geldi bana :)
    Selamlar.

  2. M. Cihat Altuntaş Post author

    Evet Tolga haklısın. Aslında eski kodda öyle bir metod yoktu yani refactoring yapmak gerekir. Örneğe uygun olsun diye yazdım ama metod adına dikkat etmemişim dikkatin için sağol ona daha uygun bir isim verelim . Beni düzeltmen çok hoşuma gitti bu da makalelerin amacına ulaştığının göstergesidir. :)

Comments are closed.