커맨드 패턴? 매크로? 뭐야?

nGyu·2025년 5월 19일
1

명령을 추상화하여, 객체로 다루는 패턴.

깃헙을 돌아다니다가 toCommand() 라는 메서드를 보게 되었다.
toEntity()나 toDto() 같은 메서드를 접해본 적 있어 아마, Command 객체로 변환하는거 같은데 처음 보는것이라 생소해 공부해보았다.

Command Pattern

메이플을 즐겨하거나 각종 게임을 즐겨하는 사람들은 이런 장면은 익숙할 수 있다.
바로 매크로 프로그램이다.


많은 사람들이 커맨드 패턴하면 쉽게 비유하는게 매크로이다. 필자도 더 좋은 예시를 알아내고 싶었는데, 이게 가장 적합한거같다...

매크로는 어떤가? 여러 이벤트를 사전에 입력해두고, 버튼 딸깍으로 모든 이벤트를 한번에 실행시킨다.
커맨드 패턴도 이와 같다.
조금 "개발자"스럽게 표현해보겠다. 여러 Command 를 Invoker 에 미리 저장해서 한번에 뽑아쓴다

"아니 이게 뭔소리야"

라고 할 수 있기에 조금 디테일하게 보겠다.

Command

어떠한 행동을 Command 라고 한다.
간단한 예제를 보자

interface Command{ void execute(); }

public class MapleChar {
	private int position = 0;

	void move() {
		position += 10;
	}

	void jump() {
		position += 20;
	}
}

public class CharMoveCommand implements Command {
	private final MapleChar mapleChar;

	public CharMoveCommand(MapleChar mapleChar) {
		this.mapleChar = mapleChar;
	}

	@Override
	public void execute() {
		mapleChar.move();
	}
}


public class CharJumpCommand implements Command {
	private final MapleChar mapleChar;

	public CharJumpCommand(MapleChar mapleChar) {
		this.mapleChar = mapleChar;
	}

	@Override
	public void execute() {
		mapleChar.jump();
	}
}

public class Game{
	public void play() {
		MapleChar player = new MapleChar();

		new CharMoveCommand(player).execute();
		new CharJumpCommand(player).execute();
	}
}

이런식으로 Reciver(MapleChar.class)의 명령을 Command 객체에서 execute 시키것을 Command 패턴이라한다.
이는 책임과 역할을 명확히 분리하고, 추상적으로 액션시키는 Command 패턴이다.

Invoker

명령을 모아서 처리하자

만약 커맨드가 여러개이고, 이 커맨드를 한번에 여러번 실행시키고 싶다면?
Invoker 에 모아서 처리하면 된다.

이 Invoker 는 앞으로 프로그래밍을 하면서 가장 많이 접하는 용어이므로, 정확히 짚고 넘어가보자.
Invoker = 실행을 트리거하는 주체

이 Invoker 는 여러 Command를 하나로 묶어, 한번에 실행시키는 역할을 한다.

public class Invoker{
	private List<Command> commandList = new ArrayList<>();

	public void push(final Command command) {
		commandList.append(command);
	}

	public void clear() {
		commandList.clear();
	}

	public void run() {
		commandList.forEach(Command::execute);
	}
}

이런식으로 간단한 Invoker 를 만들 수 있다.
현재는 커맨드들을 ArrayList 에 저장하고 있지만, 상황에 따라 Set, Queue, Stack, Map 같은 다른 자료구조도 가능하다.

굳이 왜 써야해?

간략하게 장점만 나열해보겠다.

  • 유지보수성: 명령 로직이 분리되어있어 수정 시 영향이 최소화 된다.
  • 확장성: 새로운 명령 추가 시 기존 코드의 수정을 최소화할 수 있다.
  • 테스트 용이성: 각 명령을 독립적으로 호출할 수 있다.

이정도의 장점이 있다.


정리

모든 디자인 패턴이 만능은 아니다. 프로젝트 규모에 따라 선택과 집중을 통해 그에 알맞은 패턴을 적용해야한다.

그렇지 않으면 되려 투머치한 구조가 되어버리고, 불필요한 리소스를 낭비하게 될 수 있다.
여러 패턴에 대해서 숙지하는것은 좋지만, 남들이 좋다좋다 하니까 무작정 따라하는건 좋지 않아보인다.

profile
지금보다 내일을, 모레를 준비하자

0개의 댓글