Command Pattern
1. 정의
- 요청을 캡슐화 해서 사용자가 보낸 요청에 대한 정보를 저장, 취소 등 할 수 있도록 하는 패턴
2. 설명
- 다양한 요청을 똑같은 함수의 호출로 처리 가능토록 인터페이스로 구현.
- 커맨드를 만들 때 해당 인터페이스를 상속받아 구현
- 커맨드를 저장하여 해당 커맨드의 로그를 남기거나 할 수 있다
3. 장/단점
1) 장점
- 작업 요청 로그를 남기거나 할 때 쓰면 쉽게 구현이 가능
2) 단점
- 객체의 캡슐화 하기 어려운 요청의 경우 구현이 힘들 수 있다.
4. 예제 코드
using System;
using System.Collections.Generic;
namespace CommandPattern
{
// Command 인터페이스
interface ICommand
{
// 실행
int[,] Execute();
// 되돌리기
int[,] Undo();
}
class DrawSquareCommand : ICommand
{
// 왼쪽 위 좌표
private int x1, y1;
// 오른쪽 아래 좌표
private int x2, y2;
// 사각형 색깔
private int color;
// 이전의 캔버스를 저장
private int[,] canvas;
// 현재 캔버스와 사각형 좌표들을 받음
public DrawSquareCommand(int[,] old, int x1, int y1, int x2, int y2, int color)
{
canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];
for(int i=0 ;i= x1 && i <= x2 && j >= y1 && j <= y2 )
{
resultCanvas[ i, j ] = color;
}
else
resultCanvas[ i, j ] = canvas[ i, j ];
}
}
return resultCanvas;
}
// 사각형 그리기 되돌리기
public int[,] Undo()
{
return canvas;
}
}
class DrawCircleCommand : ICommand
{
// 중심 좌표
private int x1, y1;
// 원 반지름
private int squareRadius;
// 원 색깔
private int color;
// 이전의 캔버스를 저장
private int[,] canvas;
// 현재 캔버스와 사각형 좌표들을 받음
public DrawCircleCommand(int[,] old, int x1, int y1, int radius, int color)
{
canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
canvas[ i, j ] = old[ i, j ];
}
}
this.x1 = x1;
this.y1 = y1;
squareRadius = radius * radius;
this.color = color;
}
// 사각형 그리기 실행
public int[,] Execute()
{
// 결과 값 저장할 변수
int[,] resultCanvas = new int[ canvas.GetLength( 0 ), canvas.GetLength( 1 ) ];
// 원 그림
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
if ( ( i - x1 ) * ( i - x1 ) + ( j - y1 ) * ( j - y1 ) <= squareRadius )
{
resultCanvas[ i, j ] = color;
}
else
resultCanvas[ i, j ] = canvas[ i, j ];
}
}
return resultCanvas;
}
// 원 그리기 되돌리기
public int[,] Undo()
{
return canvas;
}
}
class DrawLineCommand : ICommand
{
// 왼쪽 위 좌표
private int x1, y1;
// 오른쪽 아래 좌표
private int x2, y2;
// 사각형 색깔
private int color;
// 이전의 캔버스를 저장
private int[,] canvas;
// 현재 캔버스와 사각형 좌표들을 받음
public DrawLineCommand(int[,] old, int x1, int y1, int x2, int y2, int color)
{
canvas = new int[ old.GetLength( 0 ), old.GetLength( 1 ) ];
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
canvas[ i, j ] = old[ i, j ];
}
}
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.color = color;
}
// 사각형 그리기 실행
public int[,] Execute()
{
// 결과 값 저장할 변수
int[,] resultCanvas = new int[ canvas.GetLength( 0 ), canvas.GetLength( 1 ) ];
// 기울기를 구할 수 없을 때
if (x2 == x1)
{
// 선 그림
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
if ( i == x1 && j >= y1 && j <= y2 )
{
resultCanvas[ i, j ] = color;
}
else
resultCanvas[ i, j ] = canvas[ i, j ];
}
}
}
else
{
// 기울기
float slope = ( float ) ( y2 - y1 ) / ( x2 - x1 );
// y 절편
float yIntercept = y1 - ( x1 * slope );
// 선 그림
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
if ( i >= x1 && i <= x2 && j >= y1 && j <= y2 )
{
if ( j == ( int ) ( slope * i + yIntercept ) )
{
resultCanvas[ i, j ] = color;
}
else
resultCanvas[ i, j ] = canvas[ i, j ];
}
else
resultCanvas[ i, j ] = canvas[ i, j ];
}
}
}
return resultCanvas;
}
// 선 그리기 되돌리기
public int[,] Undo()
{
return canvas;
}
}
class CommandManager
{
// 실행취소 기록
private Stack undoHistory;
// 다시실행 기록
private Stack redoHistory;
public CommandManager()
{
undoHistory = new Stack();
redoHistory = new Stack();
}
// 명령 실행
public int[,] ExecuteCommand(ICommand com)
{
// 일반 명령 실행 시 다시 실행 기록은 삭제.
redoHistory.Clear();
// 실행할 명령을 실행취소 기록에 넣어줌.
undoHistory.Push( com );
return com.Execute();
}
// 실행 취소
public int[,] UndoCommand()
{
ICommand undoCom = undoHistory.Pop();
redoHistory.Push( undoCom );
return undoCom.Undo();
}
// 다시 실행
public int[,] RedoCommand()
{
ICommand redoCom = redoHistory.Pop();
undoHistory.Push( redoCom );
return redoCom.Execute();
}
}
class Program
{
public static void PrintCanvas(int[,] canvas)
{
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
Console.Write( canvas[ i, j ] );
Console.Write( " " );
}
Console.Write( "\n" );
}
Console.Write( "\n" );
}
public static void UpdateCanvas(int[,] canvas, int[,] newCanvas)
{
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
canvas[ i, j ] = newCanvas[ i, j ];
}
}
}
static void Main(string[] args)
{
// canvas 생성
int[,] canvas = new int[ 10, 10 ];
// canvas 초기화
for ( int i = 0 ; i < canvas.GetLength( 0 ) ; i++ )
{
for ( int j = 0 ; j < canvas.GetLength( 1 ) ; j++ )
{
canvas[ i, j ] = 0;
}
}
Console.WriteLine( "==================== 초기 캔버스 ====================" );
PrintCanvas( canvas );
// 명령 매니저 생성
CommandManager cManager = new CommandManager();
// 원 그리기 명령 생성 후 실행
DrawCircleCommand dCircle = new DrawCircleCommand( canvas, 5, 5, 3, 5 );
UpdateCanvas(canvas, cManager.ExecuteCommand( dCircle ));
Console.WriteLine( "==================== 1.원 그리기 ====================" );
PrintCanvas( canvas );
// 사각형 그리기 명령 생성 후 실행
DrawSquareCommand dSquare = new DrawSquareCommand( canvas, 4, 4, 6, 6, 3 );
UpdateCanvas( canvas, cManager.ExecuteCommand( dSquare ) );
Console.WriteLine( "================== 2.사각형 그리기 ==================" );
PrintCanvas( canvas );
// 선 그리기 명령 생성 후 실행
DrawLineCommand dLine = new DrawLineCommand( canvas, 4, 4, 6, 6, 1 );
UpdateCanvas( canvas, cManager.ExecuteCommand( dLine ) );
Console.WriteLine( "==================== 3.선 그리기 ====================" );
PrintCanvas( canvas );
// 되돌리기 명령 실행
UpdateCanvas( canvas, cManager.UndoCommand() );
Console.WriteLine( "================== 2번으로 되돌리기 =================" );
PrintCanvas( canvas );
// 되돌리기 명령 실행
UpdateCanvas( canvas, cManager.UndoCommand() );
Console.WriteLine( "================== 1번으로 되돌리기 =================" );
PrintCanvas( canvas );
// 다시 실행 명령 실행
UpdateCanvas( canvas, cManager.RedoCommand() );
Console.WriteLine( "================== 2번으로 다시실행 =================" );
PrintCanvas( canvas );
}
}
}
5. 출력 결과물
'C# > Design Pattern' 카테고리의 다른 글
| [Design Pattern C#]Singleton Pattern (0) | 2016.11.26 |
|---|