[GoF] Command 패턴

패턴명칭

Command

필요한 상황

어떤 기능이나 동작을 객체화하여 실행할 수 있는 패턴이다. 객체화된 기능은 관리되어, 실행에 대한 Undo, Redo 기능 구현이나 배치(Batch)로 처리되어 여러 개의 기능을 원하는 시점에 한번에 실행될 수 있다.

예제 코드

Command는 어떤 기능이나 동작을 객체화하기 위한 인터페이스이다. 이 Command를 구현하는 클래스들은 고유한 기능이나 동작을 수행할 수 있는 객체화가 가능하다. 먼저 Command 인터페이스는 다음과 같다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public interface Command {
public void run();
}
package tstThread; public interface Command { public void run(); }
package tstThread;

public interface Command {
	public void run();
}

다음은 Command 인터페이스를 구현하는 CleanCommand로 화면을 지우는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class ClearCommand implements Command {
@Override
public void run() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
}
package tstThread; public class ClearCommand implements Command { @Override public void run() { System.out.print("\033[H\033[2J"); System.out.flush(); } }
package tstThread;

public class ClearCommand implements Command {
	@Override
	public void run() {
		System.out.print("\033[H\033[2J");  
	    System.out.flush();  
	}
}

다음은 PrintCommand로 화면에 원하는 문자열을 출력하는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class PrintCommand implements Command {
private String content;
public PrintCommand(String content) {
this.content = content;
}
@Override
public void run() {
System.out.print(content);
}
}
package tstThread; public class PrintCommand implements Command { private String content; public PrintCommand(String content) { this.content = content; } @Override public void run() { System.out.print(content); } }
package tstThread;

public class PrintCommand implements Command {
	private String content;
	
	public PrintCommand(String content) {
		this.content = content;
	}
	
	@Override
	public void run() {
		System.out.print(content);
	}
}

다음은 MoveCommand로 출력할 위치를 지정하는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class MoveCommand implements Command {
private int x;
private int y;
public MoveCommand(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public void run() {
System.out.print(String.format("%c[%d;%df", 0x1B, y, x));
}
}
package tstThread; public class MoveCommand implements Command { private int x; private int y; public MoveCommand(int x, int y) { this.x = x; this.y = y; } @Override public void run() { System.out.print(String.format("%c[%d;%df", 0x1B, y, x)); } }
package tstThread;

public class MoveCommand implements Command {
	private int x;
	private int y;
	
	public MoveCommand(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	@Override
	public void run() {
		System.out.print(String.format("%c[%d;%df", 0x1B, y, x));
	}
}

다음은 TextColorCommand로 문자열을 출력할때 색상을 지정하는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class TextColorCommand implements Command {
public enum Color {
BLACK("\u001B[30m"), RED("\u001B[31m"),
GREEN("\u001B[32m"), YELLOW("\u001B[33m"), BLUE("\u001B[34m"),
PURPLE("\u001B[35m"), CYAN("\u001B[36m"), WHITE("\u001B[37m");
final private String code;
private Color(String name) {
this.code = name;
}
public String getCode() {
return code;
}
};
private Color color;
public TextColorCommand(Color color) {
this.color = color;
}
@Override
public void run() {
System.out.print(color.getCode());
}
}
package tstThread; public class TextColorCommand implements Command { public enum Color { BLACK("\u001B[30m"), RED("\u001B[31m"), GREEN("\u001B[32m"), YELLOW("\u001B[33m"), BLUE("\u001B[34m"), PURPLE("\u001B[35m"), CYAN("\u001B[36m"), WHITE("\u001B[37m"); final private String code; private Color(String name) { this.code = name; } public String getCode() { return code; } }; private Color color; public TextColorCommand(Color color) { this.color = color; } @Override public void run() { System.out.print(color.getCode()); } }
package tstThread;

public class TextColorCommand implements Command {
	public enum Color {
		BLACK("\u001B[30m"), RED("\u001B[31m"), 
		GREEN("\u001B[32m"), YELLOW("\u001B[33m"), BLUE("\u001B[34m"), 
		PURPLE("\u001B[35m"), CYAN("\u001B[36m"), WHITE("\u001B[37m");
		
		final private String code; 
		
		private Color(String name) { 
			this.code = name; 
		} 
		
		public String getCode() { 
			return code; 
		}
	};
	
	private Color color;
	
    public TextColorCommand(Color color) {
    	this.color = color;
    }
    
	@Override
	public void run() {
		System.out.print(color.getCode());
	}
}

다음은 BkColorCommand로 문자열을 출력할때 배경 색상을 지정하는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class BkColorCommand implements Command {
public enum Color {
BLACK("\u001B[40m"), RED("\u001B[41m"),
GREEN("\u001B[42m"), YELLOW("\u001B[43m"), BLUE("\u001B[44m"),
PURPLE("\u001B[45m"), CYAN("\u001B[46m"), WHITE("\u001B[47m");
final private String code;
private Color(String name) {
this.code = name;
}
public String getCode() {
return code;
}
};
private Color color;
public BkColorCommand(Color color) {
this.color = color;
}
@Override
public void run() {
System.out.print(color.getCode());
}
}
package tstThread; public class BkColorCommand implements Command { public enum Color { BLACK("\u001B[40m"), RED("\u001B[41m"), GREEN("\u001B[42m"), YELLOW("\u001B[43m"), BLUE("\u001B[44m"), PURPLE("\u001B[45m"), CYAN("\u001B[46m"), WHITE("\u001B[47m"); final private String code; private Color(String name) { this.code = name; } public String getCode() { return code; } }; private Color color; public BkColorCommand(Color color) { this.color = color; } @Override public void run() { System.out.print(color.getCode()); } }
package tstThread;

public class BkColorCommand implements Command {
	public enum Color {
		BLACK("\u001B[40m"), RED("\u001B[41m"), 
		GREEN("\u001B[42m"), YELLOW("\u001B[43m"), BLUE("\u001B[44m"), 
		PURPLE("\u001B[45m"), CYAN("\u001B[46m"), WHITE("\u001B[47m");
		
		final private String code; 
		
		private Color(String name) { 
			this.code = name; 
		} 
		
		public String getCode() { 
			return code; 
		}
	};
	
	private Color color;
	
    public BkColorCommand(Color color) {
    	this.color = color;
    }
    
	@Override
	public void run() {
		System.out.print(color.getCode());
	}
}

다음은 MultiCommand로 여러개의 Command 객체를 저장해 한꺼번에 실행하는 기능을 실행한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
import java.util.ArrayList;
public class MultiCommand implements Command {
private ArrayList<Command> commands = new ArrayList<Command>();
public void add(Command command) {
commands.add(command);
}
@Override
public void run() {
int cntCommands = commands.size();
for(int i=0; i<cntCommands; i++) {
Command command = commands.get(i);
command.run();
}
}
}
package tstThread; import java.util.ArrayList; public class MultiCommand implements Command { private ArrayList<Command> commands = new ArrayList<Command>(); public void add(Command command) { commands.add(command); } @Override public void run() { int cntCommands = commands.size(); for(int i=0; i<cntCommands; i++) { Command command = commands.get(i); command.run(); } } }
package tstThread;

import java.util.ArrayList;

public class MultiCommand implements Command {
	private ArrayList<Command> commands = new ArrayList<Command>();
	
	public void add(Command command) {
		commands.add(command);
	}
	
	@Override
	public void run() {
		int cntCommands = commands.size();
		for(int i=0; i<cntCommands; i++) {
			Command command = commands.get(i);
			command.run();
		}
	}
}

지금까지의 클래스를 사용하는 예제 코드는 다음과 같다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package tstThread;
public class Main {
public static void main(String[] args) {
MultiCommand redTextWhiteBkColorCommand = new MultiCommand();
redTextWhiteBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.RED));
redTextWhiteBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.WHITE));
MultiCommand blackTextGreenBkColorCommand = new MultiCommand();
blackTextGreenBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.BLACK));
blackTextGreenBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.GREEN));
MultiCommand endCommand = new MultiCommand();
endCommand.add(new TextColorCommand(TextColorCommand.Color.WHITE));
endCommand.add(new BkColorCommand(BkColorCommand.Color.BLACK));
endCommand.add(new MoveCommand(0, 24));
endCommand.run();
MultiCommand yellowTextRedBkColorCommand = new MultiCommand();
yellowTextRedBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.YELLOW));
yellowTextRedBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.RED));
Command clear = new ClearCommand();
clear.run();
redTextWhiteBkColorCommand.run();
(new MoveCommand(10, 2)).run();
(new PrintCommand("GIS")).run();
blackTextGreenBkColorCommand.run();
(new MoveCommand(60, 4)).run();
(new PrintCommand("Developer")).run();
yellowTextRedBkColorCommand.run();
(new MoveCommand(30, 6)).run();
(new PrintCommand("Dip2K")).run();
endCommand.run();
}
}
package tstThread; public class Main { public static void main(String[] args) { MultiCommand redTextWhiteBkColorCommand = new MultiCommand(); redTextWhiteBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.RED)); redTextWhiteBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.WHITE)); MultiCommand blackTextGreenBkColorCommand = new MultiCommand(); blackTextGreenBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.BLACK)); blackTextGreenBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.GREEN)); MultiCommand endCommand = new MultiCommand(); endCommand.add(new TextColorCommand(TextColorCommand.Color.WHITE)); endCommand.add(new BkColorCommand(BkColorCommand.Color.BLACK)); endCommand.add(new MoveCommand(0, 24)); endCommand.run(); MultiCommand yellowTextRedBkColorCommand = new MultiCommand(); yellowTextRedBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.YELLOW)); yellowTextRedBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.RED)); Command clear = new ClearCommand(); clear.run(); redTextWhiteBkColorCommand.run(); (new MoveCommand(10, 2)).run(); (new PrintCommand("GIS")).run(); blackTextGreenBkColorCommand.run(); (new MoveCommand(60, 4)).run(); (new PrintCommand("Developer")).run(); yellowTextRedBkColorCommand.run(); (new MoveCommand(30, 6)).run(); (new PrintCommand("Dip2K")).run(); endCommand.run(); } }
package tstThread;

public class Main {
	public static void main(String[] args) {
		MultiCommand redTextWhiteBkColorCommand = new MultiCommand();
		redTextWhiteBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.RED));
		redTextWhiteBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.WHITE));
		
		MultiCommand blackTextGreenBkColorCommand = new MultiCommand();
		blackTextGreenBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.BLACK));
		blackTextGreenBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.GREEN));
		
		MultiCommand endCommand = new MultiCommand();
		endCommand.add(new TextColorCommand(TextColorCommand.Color.WHITE));
		endCommand.add(new BkColorCommand(BkColorCommand.Color.BLACK));
		endCommand.add(new MoveCommand(0, 24));
		endCommand.run();
		
		MultiCommand yellowTextRedBkColorCommand = new MultiCommand();
		yellowTextRedBkColorCommand.add(new TextColorCommand(TextColorCommand.Color.YELLOW));
		yellowTextRedBkColorCommand.add(new BkColorCommand(BkColorCommand.Color.RED));
		
		Command clear = new ClearCommand();
		clear.run();
		
		redTextWhiteBkColorCommand.run();
		(new MoveCommand(10, 2)).run();
		(new PrintCommand("GIS")).run();
		
		blackTextGreenBkColorCommand.run();
		(new MoveCommand(60, 4)).run();
		(new PrintCommand("Developer")).run();
		
		yellowTextRedBkColorCommand.run();
		(new MoveCommand(30, 6)).run();
		(new PrintCommand("Dip2K")).run();
		
		endCommand.run();
	}
}

실행결과는 다음과 같다.

이 글은 소프트웨어 설계의 기반이 되는 GoF의 디자인패턴에 대한 강의자료입니다. 완전한 실습을 위해 이 글에서 소개하는 클래스 다이어그램과 예제 코드는 완전하게 실행되도록 제공되지만, 상대적으로 예제 코드와 관련된 설명이 함축적으로 제공되고 있습니다. 이 글에 대해 궁금한 점이 있으면 댓글을 통해 남겨주시기 바랍니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다