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 |
---|