Komut Tasarım Kalıbı (Command Design Pattern)

Eyl 08, 2013
Davranışsal (Behavioral) tasarım kalıplarından biri olan komut tasarım kalıbı, nesneye dayalı programlama (Object Oriented Programing) çalışmalarında çoğu zaman farkında olmadan kullanılan bir yapıdır. Komut tasarım kalıbı, kullanıcı isteklerini gerçekleştiren kod yapısının sarmalanarak nesneler halinde saklanmasına dayanır. Öyle ki üzerinde çalışılacak nesnenin tanımının yapılamadığı durumlar olabilir. Bu şartlarda ne tür çözüm yolları ile nesneye müdahale edilmeye çalışılabileceği kestirilemez, ancak gerçekleştirilmek istenen işlemler bir nesne olarak sarmalanır. Nesne halinde tutulan bu sarmal kod yapısı, alıcı nesne için bir çözüm oluşturur. Çözümlerin nesneler halinde saklanmasının getirisi olarak da komut tasarım kalıbı aynı kod yapısının tekrar tekrar kullanılabilmesine olanak sağlar.

Komut tasarım kalıbının kullanıldığı tüm durumlarda geçerli olan bazı ortak terimler mevcuttur. Açıklamaları ile beraber bunlar;
  • Komut (Command) : Gerçekleştirilecek işlem için bir ara yüz tanımlar.
  • Somut Komut (Concrete Command): Alıcı ve gerçekleştirilecek işlemler arasında bir bağ kurar, alıcıda karşılık düşen işlemleri çağırarak çalıştırma eylemini gerçekleştirir.
  • İstemci (Client): Komut nesnesini oluşturur ve metodun sonraki zamanlarda çağrılabilmesi için gerekli bilgiyi sağlar.
  • Çağırıcı (Invoker): Metodun ne zaman çağrılacağını belirtir.
  • Alıcı (Receiver):  Kullanıcı isteklerini gerçekleştirecek asıl metod kodlarını içerir.
Komutların nesne halinde tutulmasının getirdiği bir fayda olarak istenildiği durumlarda bu nesnelere yaptıkları işlemleri geri almak da öğretilebilir. Bunun sonucu olarak Yinele(Redo)/Geri Al(Undo) işlemleri gerçeklenebilir ve bir makro özelliği yaratılabilir.

Komut tasarım kalıbı için UML diyagramı :

 

Komut Tasarım Kalıbı İle İlgili Uygulama:

Verilen uygulamada akış sırası kod içerisinde özellikleri belirtilmiş Kullanici sınıfından  kullanici adında bir nesne oluşturulması ile başlar. Kullanici sınıfı içerisinde bu sınıftan türetilmiş her nesne için yine özellikleri kod içerisinde belirtilmiş Hesap sınıfından hesap adında bir diğer nesne oluşturulur. Hesap sınıfı ise mevcut değişken ve belirtilen değişken arasında belirtilen operatöre karşılık gelen işlemin gerçekleştirildiği kısımdır. Gerçekleştirilen her işlem bir seviye belirtir ve her seviyede çalışan komut, komut listesine yeni bir eleman olarak eklenir. Yapılan işlemleri geri almak için mevcut değişken üzerinde o ana kadar gerçekleşmiş olan işlemler komut listesinden alınır, GeriAl fonksiyonu ile tersi işlemler oluşturulur ve istenen seviye kadar geri dönülür. Yapılan işlemleri yinelemek için ise yine aynı düşünce ile o ana kadar gerçekleşmiş olan işlemler komut listesinden alınır, IleriAl fonksiyonu ile istenen seviye kadar yinelenir.
 

using System;
using System.Collections.Generic;
namespace KomutKalibi
{
    class MainApp

    {
        static void Main()

        {
            Kullanici kullanici = new Kullanici();
            kullanici.Hesapla('+', 100);
            kullanici.Hesapla('-', 50);
            kullanici.Hesapla('*', 10);
            kullanici.Hesapla('/', 2);
            kullanici.GeriAl(4);
            kullanici.IleriAl(3);
            Console.ReadKey();
        }
    }
    abstract class Komut
    {
        public abstract void Uygula();
        public abstract void Uygulama();
    }
    class HesapKomutu : Komut
    {
        private char _islemTuru;
        private int _islenen;
        private Hesap _hesap;
        public HesapKomutu(Hesap hesap, char @islemTuru, int islenen)
        {
            this._hesap = hesap;
            this._islemTuru = @islemTuru;
            this._islenen = islenen;
        }
        public char IslemTuru
        {
            set { _islemTuru = value; }
        }
        public int Islenen
        {
            set { _islenen = value; }
        }
        public override void Uygula()
        {
            _hesap.Islem(_islemTuru, _islenen);
        }
        public override void Uygulama()
        {
            _hesap.Islem(GeriAl(_islemTuru), _islenen);
        }
        private char GeriAl(char @islemTuru)
        {
            switch (@islemTuru)
            {
                case '+': return '-';
                case '-': return '+';
                case '*': return '/';
                case '/': return '*';
                default: throw new
                 ArgumentException("@islemTuru");
            }
        }
    }
    class Hesap
    {
        private int _mevcut = 0;
        public void Islem(char @islemTuru, int islenen)
        {
            switch (@islemTuru)
            {
                case '+': _mevcut += islenen; break;
                case '-': _mevcut -= islenen; break;
                case '*': _mevcut *= islenen; break;
                case '/': _mevcut /= islenen; break;
            }
            Console.WriteLine("Mevcut değer = {0,3} (İşlem türü: {1}, İşlenen: {2})", _mevcut, @islemTuru, islenen);

        }
}
    class Kullanici
    {
        private Hesap _hesap = new Hesap();
        private List<Komut> _komutlar = new List<Komut>();
        private int _mevcut = 0;
        public void IleriAl(int seviye)
        {
            Console.WriteLine("\n---- İleri Al {0} seviye ", seviye);         
            for (int i = 0; i < seviye; i++)
            {
                if (_mevcut < _komutlar.Count - 1)
                {
                    Komut komut = _komutlar[_mevcut++];
                    komut.Uygula();
                }
            }
        }
        public void GeriAl(int seviye)
        {
            Console.WriteLine("\n---- Geri Al {0} seviye ", seviye);          
            for (int i = 0; i < seviye; i++)
            {
                if (_mevcut > 0)
                {
                    Komut komut = _komutlar[--_mevcut] as Komut;
                    komut.Uygulama();
                }
            }
        }
        public void Hesapla(char @islemTuru, int islenen)
        {
            Komut komut = new HesapKomutu(_hesap, @islemTuru, islenen);
            komut.Uygula();
            _komutlar.Add(komut);
            _mevcut++;
        }
    }
}

Uygulamanın ekran çıktısı aşağıdaki gibidir :