Command Tasarım Kalıbı

By in Blog on 10/02/2015
Belki biliyorsunuz, tarihte Design Pattern’ler ilk olarak yazılımcılar tarafından değil bir mimar tarafından tanımlanmış. Sonrasında yazılım sektöründe yer almış, genişlemiş, gelişmiş ve çokça kabul görmüştür. Çünkü başka bir mühendislik dalı yoktur ki ürün değişmek-değişebilmek üzerine tasarlansın ve değişebiliyor olması onun başarılı sayılabilmesi için en önemli kriter olarak sayılsın. İşte tasarım şablonları bu değişime uygun, çevik, yönetilebilir, gelişebilir, anlaşılabilir yazılım ürünleri geliştirebilmenin yolu olarak ortaya çıkmışlardır. Yani bir anlamda zaten soyut olan yazılım bilimindeki best practice ve yöntemler üzerindeki soyutlamalardır. Ancak, prensip ve çerçevesi belli kavram ve metodolojiler olarak tanımlanabildikleri için tanımlanabilen sorunlar için sağlıklı ve tecrübe edilmiş bir çözüm sağlarlar. Böylece alanındaki insanlar, paydaşlar birbirlerinin dilinden anlar, kültür ve tecrübe aktarılarak aynı yanlışlara düşülmeden gelecek gelişerek inşa olabilir. Ayrıca bilişim alanında bilinen ve kaliteli iş yapmayı ilke edinilerek motto haline gelen  “Şiir gibi kod yazma” terimi ile ayrılmaz bir bütünü oluştururlar. Bu şablonları benimsemek ve nerede nasıl hangi problemin çözümünde kullanılabileceğine çaba göstermek/kafa yormak; Nesne merkezli dillerin procedural olarak kullanımına meyledilmesine de engel olur ve defalarca birçok sorunun çözümünde rehber olabilirler. Esasında bir çok yapıda bulunur ve kod geliştiricileri olarak genellikle framework bazında kullanırız ancak derinlemesine bakılmadığından bu soyut kavramları göremeyebiliriz. Tasarım kalıpları, (yada şablonları, farklı formları var ancak sanırım ikisi de kabul görmüşler)yazılım mimarisinde özellikle nesne merkezli dillerde öne çıkan “Düşük birliktelik, yüksek bağımlılık (High Cohesion Low Coupling)” kavramlarının merkezindelerdir.

Tasarım kalıplarını öğreniyorum

Ben de bu tasarım kalıplarıyla pek tabii ilgileniyorum ve bilmediklerimi yada bilerek yada bilmeyerek kullandıklarımı araştırarak öğreniyorum. Okuduğumuzu / öğrendiğimizi anlayalım misali bu yazıyla ben de pekiştirmiş olayım :)
Bunlardan biri olan Command Design Pattern ine bakalım.

public void actionPerformed(ActionEvent e)
{
Object o = e.getSource();
if (o instanceof YeniDosyaAc)
doFileNewAction();
else if (o instanceof DosyaAc)
doFileOpenAction();
else if (o instanceof SonErisilenDosyaAc)
doFileOpenRecentAction();
else if (o instanceof DosyaKaydet)
doFileSaveAction();
// do something
}

Böyle bir kod gördüğünüzde bir şeylerin tasarım anlamında yanlış olduğunu ancak doğru bir yaklaşımla nasıl düzeltilebileceğini ön göremediyseniz command pattern ile bunun nasıl güzelleştirilebileceğini birazdan görebilirsiniz.
  • Her birinde bir execute methodu olan aksiyon sınıflarını Command isimli bir arayüzden implemente ettiğimizi düşünün.
  • Çalışmaya (bunu interface deki execute metodu sağlar) hazır Command nesneleri oluşturulur.
  • Bu nesneler Execute methodunun çağrımının istendiği zaman yapılabileceği ortak bir methoda geçilir.
  • Metodu çağıracak olan sınıf özelleştirilmiş Command sınıflarının içinde olup biten iş mantığı hakkında hiç bir bilgi sahibi olmaz. Basitçe ilgili nesnenin methodunu tetikler. İşte arzu edildiği gibi düşük seviyeli bağlı bir soyutlama gerçekleştirilmiş oldu.
Bir çok uygulama alanı mevcut, bu bilgiler ışığında hemen akla hızlıca gelenlere göz atarsak;
  • Menü bileşenlerinde tetiklenen komutlar
  • Bir media üzerinde oynatma/durdurma/ileri alma gibi işlerde kullanımı
  • Progress bar lar

İlk başta örneklediğimiz kodu pattern ile güzelleştirelim şimdi.

Class diagram çizilmeden önce her zaman soyutlama, çok yönlülük(polimorphysm), güvenlik, OOP principles gibi ilkeleri gözeterek tasarım sırasında yada geliştirme sırasındaki tekrar tasarıma dönülme esnasında hangi interface lerin yaratılabileceği yönünde kafa yormak gerekebilir. Büyük yazılım projelerinde bunu görmesi beklenen kişi bu sebeple her zaman biraz suyun üstünde kalmalı görüşü de hakimdir. 

Şimdi diğer aksiyon sınıflarının kullanacağı arayüz sınıfını yaratalım öncelikle.
public interface Command
{
  public void execute();
}

Bunun uygulandığı bir Command sınıfı da şöyle olacaktır.

public class YeniDosyaAc extends JMenuItem implements Command
{
public void execute()
{
// iş yapan kodlar buraya gelir
}
}

Bu aksiyonları dinleyen ve sonra invoke eden sınıfımızın metodu da aşağıdaki kadar sade, okunabilir, değişime açık bir hale gelebilir.

public void actionPerformed(ActionEvent e)
{
Command command = (Command)e.getSource();
command.execute();
}

  • if statetment lardan kurtulduk.
  • Herkes kendi business logic ini bilir ve ilgilenir oldu. (Kendini bilmek mühim:)
  • Gelecekteki olası command işleri için bir iş yapış şekli oluştu, Command interface i ben buradayım diyor. (Ha sizden sonrakiler ısrarla bunu kullanmazsa sizden günah gitmiştir yapacak bir şey yok:)

Bu örnek, aslında Java daki AbstractAction class ı ile daha güzel bir halde de yazılabilirdi. Tabi sınır yok, çokça söylendiği gibi en iyi kod hiç yazılmamış olandır.

Bu kalıbın da bir çok kullanımı ve incelemesi mevcuttur. Hatta çok yönlü senaryolardaki kullanımları tartışılabilir. Akın Hoca’nın Singleton patterninin parallel thread kullanımında değindiği nüanslar ilgi çekici.

Command Pattern i inceleyenlerden Strategy Pattern hakkında bilgi sahibi olanlar iki pattern i benzetebilirler. Strategy pattern in Command Pattern den farkını buradan görebilirsiniz.
(Visited 97 times, 1 visits today)

Leave a Reply

Your email address will not be published. Required fields are marked *