3 Eylül 2013 Salı

COMMAND PATTERN NEDİR ( C++ UNDO İLE )

              
      Command Pattern yapısı çok kullanılan ve benimde sevdiğim pattern yapılarından biridir. Bu yapı temel metod çağrışımlarını birbirinden soyutlamayı amaçlar. Peki ne anlama geliyor bu açıklamaya çalışalım.

          
      Commad Patternde genel olarak hep bir buton kalıbı geçer yani runtime anında durumları değişikliğe uğraması. Durumlar değişirken bir nesne istek yapar ve o isteği başka bir nesne alıp gerçekler. Gerçekleme durumunun nasıl olduğundan istek yapan nesne sorumlu değildir. Böylelikle isteği yapan ve onu alan nesneyi birbirinden ayırmış oluyoruz. Bu işlemi program kısmında nasıl gerçekliyoruz birde ona bakalım şimdi. 



Yandaki Command Pattern uml diagramındır. Şekilde de görüldüğü gibi tüm komutlarımız ( Command) commaand base sınıfı altında tek bir arayüzde toplanmıştır. Bu bize kontrol panelindeki butonlara Command tipinde nesneler atamamızı sağlamaktadır. Yapılmasını istediğimiz her bir istek için yeni bir Command sınıfı oluşturmamız gerekmektedir.

          Ben yazdığım programda 3 farklı cihazı tek bir kontrol panelinden yönetmeyi sağlayan basit bir yapı oluşturmuştur. Aşağıdaki kod kısmında da göreceğimiz gibi bir kumanda yardımıyla birden çok cihazı kontrol edebiliyoruz. Tabi bu kontrol edilebilecek cihazların sayısı, türü, ve konbinasyonları tamamen bizim isteklerimize ve ihtiyaçlarımıza bağlıdır.

Undo:   

Command pattern yapısında çok araştırılan diğer bir yapıda undo kalıbıdır. Undo kalıbı en son yaptığımız işlemi geri almamızı sağlar aynı evlerimizdeki televizyon kumandalarında olduğu gibi. Programa uygulanması ise oldukça kolaydır yapmamız gereken Command base sınıfına undo fonksiyonu ekleyip her bir komutun yaptığı işlemi tam tersi şekilde yapmasını sağlamaktır. Kontrol panelinde undo komutunu çalıştırmak için ek bir fonksiyon yazmamız undo komutu için yeterlidir. Anlattıklarıma birde kod üzerinde bakarsak daha anlaşılır olacaktır.

Kod :


#include <iostream>
#include<string>

using namespace std;

/////////////////////////////////////////////////////
//    Kumandanın işlem yapıcağı classlar
/////////////////////////////////////////////////////

class Light
{
private:
       string name;

public:
       Light(string x) : name(x){}
       ~Light(){}

       void On()
       {
             cout << name <<" Light on ..." << endl;
       }

       void Off()
       {
             cout << name <<" light off ..." << endl;
       }
};

class Tv
{
private:
       string name;

public:
       Tv(string x) : name(x){}
       ~Tv(){}

       void On()
       {
             cout << name << " Tv on..." << endl;
       }
       void SetVolume()
       {
             cout << name << " Volume : 15 ..." << endl;
       }
       void setChannel()
       {
             cout << name << " Channel : 1 ..." << endl;
       }

       void Off()
       {
             cout << name << " Tv off..." << endl;
       }
};

/////////////////////////////////////////////////////
//    Üstteki sınıfların commandleri
/////////////////////////////////////////////////////

class Command
{

public:
       Command(){}
       ~Command(){}

       virtual void execute() = 0;   // komutlarımızın çalışmasını sağlıyan fonksiyon.
       virtual void undo() = 0;       // bir önceki komutu çalıştıracak fonksiyon.
        
};

class lightOnCommand : public Command
{
private:
       Light *light;

public:
       lightOnCommand(Light *light)
       {
             this->light = light;
       }

       ~lightOnCommand(){}

       void execute()
       {
             light->On();
       }
       void undo()
       {
             light->Off();
       }
};

class lightOffCommand : public Command
{
private:
       Light *light;

public:
       lightOffCommand(Light *light)
       {
             this->light = light;
       }
       ~lightOffCommand(){}

       void execute()
       {
             light->Off();
       }
       void undo()
       {
             light->On();
       }
};


class TvOnCommand : public Command
{
private:
       Tv *tv;

public:
       TvOnCommand(Tv *tv)
       {
             this->tv = tv;
       }
       ~TvOnCommand(){}

       void execute()
       {
             tv->On();
             tv->setChannel();
             tv->SetVolume();
       }
       void undo()
       {
             tv->Off();
       }
};

class TvOffCommand : public Command
{
private:
       Tv *tv;

public:
       TvOffCommand(Tv *tv)
       {
             this->tv = tv;
       }
       ~TvOffCommand(){}

       void execute()
       {
             tv->Off();

       }
       void undo()
       {
             tv->On();
             tv->setChannel();
             tv->SetVolume();
       }
};

class NoCommand : public Command
{
public:
       NoCommand(){}
       ~NoCommand(){}
       void execute()
       {
             cout << "NoCommand..." << endl;
            
       }
       void undo()
       {
             cout << "NoCommand..." << endl;
            
       }
};

/////////////////////////////////////////////////////
//    Kontrol paneli yani kumanda
/////////////////////////////////////////////////////

class RemoteControl
{

private:
       static const int slot = 4;      // kumandamızın tuş sayısı.
       Command *OnSlot[slot];
       Command *OffSlot[slot];
       Command *noCommand;
       mutable Command *undo;

public:
       RemoteControl()
       {
             noCommand = new NoCommand();
             for (int i = 0; i < slot; i++)
             {
                    OnSlot[i] = noCommand;   // başlangiçta boş oldukları için yapılandırıcıda 
                    OffSlot[i] = noCommand;  // nocommand olarak değer ataması yapılır...
             }
             undo = noCommand;
       }
       ~RemoteControl()
       {
             delete noCommand;
       }

       void setCommand(int slot, Command* onCommand, Command* offCommand){
             OnSlot[slot] = onCommand;     // kumandamızın on ve off butonlarına atama
             OffSlot[slot] = offCommand;   // yapmak için set fonksiyonumuz
       }

       void onButtonWasPushed(int slot) const
       {
             OnSlot[slot]->execute();      // girilen slottaki on buton çalışacak
             undo = OnSlot[slot];
             cout << "---------------------------------" << endl;
       }

       void offButtonWasPushed(int slot) const
       {
             OffSlot[slot]->execute();     // girilen slottaki off buton çalışacak
             undo = OffSlot[slot];
             cout << "---------------------------------" << endl;
       }
       void undoButtonWasPushed()
       {
             undo->undo();
             cout << "---------------------------------" << endl;
       }
};

       int main()
       {
             RemoteControl *remoteControl = new RemoteControl(); // Kumandamızı oluşturuyoruz.

             Light *kitchenLight = new Light("Kitchen"); ///
             Light *bathRoomlight = new Light("Bath Room");  ///  kontrol edilecek aletlerimizi oluşturuyoruz.
             Tv *tv = new Tv("Television");            ///  

             lightOnCommand *KitchenLightOn = new lightOnCommand(kitchenLight);
             lightOffCommand *KitchenLightOff = new lightOffCommand(kitchenLight);
            
             lightOnCommand *BathroomLightOn = new lightOnCommand(bathRoomlight);
             lightOffCommand *BathroomLightOff = new lightOffCommand(bathRoomlight);
              
             TvOnCommand *tvOn = new TvOnCommand(tv);      //  bu kısımda ise on ve off buton pointer
             TvOffCommand *tvoff = new TvOffCommand(tv);   //  oluşturuyoruz.

             remoteControl->setCommand(0, KitchenLightOn, KitchenLightOff);     //
             remoteControl->setCommand(1, BathroomLightOn, BathroomLightOff);  //   kuamandamızın tuşlarına değerleri atıyoruz.
             remoteControl->setCommand(2, tvOn, tvoff);                       //

             remoteControl->onButtonWasPushed(0);
             remoteControl->onButtonWasPushed(2);
             remoteControl->onButtonWasPushed(1);
             remoteControl->offButtonWasPushed(0);
             remoteControl->undoButtonWasPushed();
             remoteControl->offButtonWasPushed(2);
             remoteControl->onButtonWasPushed(3);
             remoteControl->undoButtonWasPushed();


             system("pause");
             return 0;

       }

Output : 




Programımızda da görüldüğü gibi tüm komutlar tek bir nesne üzerinden yürütülüyor yani kontrol panelinden. Command Pattern özelliği de bu kısım için geçerlidir. İstek yapılır ama isteğin nasıl gerçekleştirildiği bizi ilgilendirmez. Undo komutları çıktımız da da görüldüğü gibi en son yapılan işlemi geri almaktadır.

Zaman ayırdığınız için teşekkürler J
Lütfen yorum yapınız ...




Hiç yorum yok:

Yorum Gönder