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.
#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;
}
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.