17. 명령 패턴(Command Pattern)
17.1 개요
프로그래밍하다 보면 명령을 내리는 개체와 명령을 수행하는 개체를 나누는 작업은 매 번 있는 작업입니다. 그런데 실제 요청한 작업을 수행하는 개체에서 수행에 필요한 알고리즘을 모두 포함하였을 때 비슷한 형태의 여러 메서드를 구현해야 하는 경우가 발생합니다. 경우에 따라서는 명령을 내리는 시점과 실제 명령을 수행하는 시점이 다르고 다양한 설정에 따라 구체적인 수행 알고리즘이 다른 경우도 발생합니다. 이 같은 경우에 명령을 내리는 곳에서 일부 알고리즘을 정의하여 명령을 수행하는 개체의 메서드를 호출할 때 입력 인자로 전달하는 것이 더 효과적입니다. 이러한 경우에 명령 패턴을 사용합니다.
명령 패턴은 명령을 요청하는 곳에서 수행할 알고리즘을 정의하여 입력 인자로 전달하면 명령을 수행하는 곳에서는 전달받은 알고리즘을 이용합니다. 이를 위해 명령을 수행하는 형식의 특정 메서드에는 수행에 필요한 알고리즘의 추상적 정의를 합니다. 명령을 요청하는 곳에서는 재정의를 통해 구체화된 알고리즘을 구현하고 이를 입력 인자로 전달하여 명령을 내리게 됩니다. 이를 통해 명령을 수행하는 형식 개체에서는 전달받은 알고리즘 개체를 이용하여 명령을 수행할 수 있게 됩니다.
이와 같은 명령 패턴을 사용하게 되면 대부분의 알고리즘은 같지만 일부 알고리즘이 다르게 적용하여 개발 비용을 줄일 수 있습니다. 이 외에도 추상적인 행위에 대한 약속과 구체적인 행위에 대한 구현을 분리를 하기 때문에 명령을 수행하는 개체 형식에서 세부적인 알고리즘을 정의하지 않을 수 있어 업무 분담에 효율을 높일 수가 있습니다.
일반적으로 메뉴나 여러 작업을 트랜잭션 형태로 수행해야 하는 경우와 다양한 콜백을 구현하는 경우에 사용되고 있습니다.
17. 2 시나리오
EH Camera 회사의 개발 팀과 몇 번의 작업을 같이 진행하면서 객원 감수자로 활동을 하게 되었어요. 객원 감수라고 직함은 주어졌지만 매 주 금요일 저녁에 이 매핑 씨와 저녁을 먹으면서 이런 저런 얘기를 나누는 것이 저에게 요구한 전부예요.
직함이라는 것은 용하게도 사람에게 주어진 이름만큼의 책임감을 느끼게 하는 것 같아요. 책임감 때문인지 모르겠지만 그 동안 개발한 S/W 모듈들의 구조들을 살펴보면서 사진 관리자 모듈이 무겁다는 것을 알게 되었죠. 개발 팀에게 이에 대한 상세 기술 문서를 요청하여 살펴보니 사진에 대한 정보를 보여주는 부분이나 삭제하는 부분 등에서 각종 메서드들이 즐비하게 나열되어 있더군요. 오늘 이 매핑씨와 저녁 식사를 할 때 이를 개선할 방법에 대하여 얘기해야겠어요.
"사진에 특정 행위를 수행할 수 있다는 추상적인 약속과 이에 대한 구체적인 구현을 분리를 하면 사진 관리자 모듈이 가벼워지고 개발 분담이 쉬워질 것 같아요."
//Common.h
#pragma once
#pragma warning (disable:4996)
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <iomanip>
using std::ios;
#include <algorithm>
#pragma warning(disable:4482)
//Picture.h
#pragma once
#include "common.h"
class Picture
{
string name;
string user;
public:
Picture(string name,string user)
{
this->name = name;
this->user = user;
}
~Picture()
{
cout<<name<<"파일 삭제"<<endl;
}
string GetName()const
{
return name;
}
string GetUser()const
{
return user;
}
};
//Command.h
#pragma once
#include "Picture.h"
class Command
{
public:
virtual void Execute(Picture *picture)=0;
};
//CommandAlgorithm.h
#include "Command.h"
class ViewPicture:
public Command
{
public:
void Execute(Picture *picture)
{
cout<<"사진 파일명:"<<picture->GetName()<<endl;
}
};
class ViewVerifyPicture:
public Command
{
public:
void Execute(Picture *picture)
{
cout<<"[사진 파일명]"<<picture->GetName();
cout<<" [소유자] "<<picture->GetUser()<<endl;
}
};
class DisposePicture:
public Command
{
public:
void Execute(Picture *picture)
{
delete picture;
}
};
//PictureManager.h
#pragma once
#include "Picture.h"
#include "Command.h"
typedef vector<Picture *> Pictures;
typedef vector<Picture *>::iterator PIter;
class PictureManager
{
Pictures pictures;
public:
void AddPicture(string name,string user)
{
pictures.push_back(new Picture(name,user));
}
void DoItAllPicture(Command *command)
{
PIter seek = pictures.begin();
PIter end = pictures.end();
for( ; seek != end ; ++seek)
{
command->Execute(*seek);
}
}
};
//UIPart.h
#pragma once
#include "CommandAlgorithm.h"
#include "PictureManager.h"
class UIPart
{
PictureManager *pm;
Command *commands[2];
string user;
public:
enum CommandEnum
{
VIEW,
VIEW_VERIFY
};
UIPart(void);
~UIPart(void);
void Login(string user);
void SavePicture(string name);
void DoItCommand(CommandEnum cmd);
};
//UIPart.h
#include "UIPart.h"
UIPart::UIPart(void)
{
pm = new PictureManager();
commands[0] = new ViewPicture();
commands[1] = new ViewVerifyPicture();
user="";
}
UIPart::~UIPart(void)
{
DisposePicture *dp = new DisposePicture();
pm->DoItAllPicture(dp);
delete dp;
delete pm;
}
void UIPart::Login(string user)
{
this->user = user;
}
void UIPart::SavePicture(string name)
{
if(user == ""){ cout<<"먼저 로긴을 하십시오."<<endl; }
else { pm->AddPicture(name,user); }
}
void UIPart::DoItCommand(CommandEnum cmd)
{
pm->DoItAllPicture(commands[cmd]);
}
//Demo.cpp
#include "UIPart.h"
int main()
{
UIPart *up = new UIPart();
up->Login("홍길동");
up->SavePicture("현충사의 봄");
up->Login("강감찬");
up->SavePicture("독립기념관의 꽃");
up->DoItCommand(UIPart::CommandEnum::VIEW);
up->DoItCommand(UIPart::CommandEnum::VIEW_VERIFY);
delete up;
return 0;
}
|
'프로그래밍 기술 > Escort GoF의 디자인 패턴' 카테고리의 다른 글
22. 감시자 패턴(Observer Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
---|---|
21. 메멘토 패턴(Memento Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
20. 중재자 패턴(Mediator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
19. 반복자 패턴(Iterator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
18. 해석자 패턴(Interpreter Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
16. 책임 연쇄 패턴(Chain of Responsibility Pattern)[Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
15. 프락시 패턴(Proxy Pattern) - 스마트 참조자 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
14. 프락시 패턴(Proxy Pattern) - 보호용 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
13. 프락시 패턴(Proxy Pattern) - 가상 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
12. 프락시 패턴(Proxy Pattern) - 원격지 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |