[디자인 패턴] Command Pattern

벼랑 끝 코딩·2025년 3월 16일

Design Pattern

목록 보기
2/6

정해진 보기가 주어지고 선택 시 알맞게 대응해야 하는 상황.
특정한 요청이나 명령에 준비된 응답을 주어야 하는 상황.
이러한 상황은 심심치 않게 맞이할 수 있다.

Command Pattern은 이러한 상황에 사용할 수 있는 디자인 패턴이다.

커맨드 패턴 사용 전

도서관을 이용하는 경우를 살펴보자.
도서 대출, 반납, 연체 시 페널티 부과와 같은 행동 패턴이 발생하고
각 행동에는 정형화된 대응을 수행할 수 있다.

if (도서 대출) {
	// 도서 대출 서비스 코드
}

if (도서 반납) {
	// 도서 반납 서비스 코드
}

if (도서 연체) {
	// 도서 연체 시 페널티 부과 서비스 코드
}

대출, 반납, 연체와 같은 상황 이외에도
도서 연장, 도서 파손 등 행동 패턴이 늘어나는 경우에는 계속해서 if문을 추가한다.
if문이 아니라 메서드라면 메서드를 추가로 생성해야할 것이다.

몇가지 단순한 행동 패턴에는 적절하게 사용될 수 있지만,
계속해서 늘어나 10개, 100개까지 늘어나게 된다면 정말 지저분한 코드가 될 것이다.
적절하게 관리할 수 있는 방법은 없을까?

커맨드 패턴

커맨드 패턴이란, 요청이나 명령을 객체화하는 디자인 패턴을 의미한다.
if문을 사용하지 않고, 특정한 행동 패턴을 클래스로 설계해서 관리하는 것이다.

interface Book {
	public void service();
}

class BookRental implements Book {

	@Override
	public void service() {
    	// 도서 대출 코드
    }
}

class BookReturn implements Book {

	@Override
	public void service() {
    	// 도서 반납 코드
    }
}

class BookOverdue implements Book {

    @Override
	public void service() {
    	// 도서 연체 시 대응 코드
    }
}

역할 분리

커맨드 패턴의 특징은 요청이나 명령을 객체화함과 동시에
호출자와 수행자의 개념을 나누어 역할을 분리한다는 것이다.

호출자가 객체화한 명령을 호출하면 수행자가 행동을 수행하도록 호출한다.
호출자 → 명령 호출 → 수행 순서로 동작한다.

class Staff {
	
    public void work() {
    	// 도서 대출
        // machine : 호출자, BookRental : 명령, Rental : 수행자
    	machine.setCommand(new BookRental(new Rental()));  // ** 명령 세팅 **
        machine.execute();  // ** 명령 실행 **
    }
}

먼저 호출자를 분리하면 Staff 클래스는 명령의 종류나 수에 구애받지 않게 된다.
명령이 어떤 것인지는 관계 없이 호출자를 통하여 명령의 수행만을 지시하면 된다.
명령의 종류가 늘어나면 객체를 구현하면 되기 때문에,
Staff 클래스는 내부의 명령 체계나 구조를 전혀 신경쓰지 않아도 된다.

class BookRental implements Book {

	private Rental rental;

	public BookRental(Rental rental) {
    	this.rental = rental;  // ** 수행자 설정 **
    }

	@Override
	public void service() {
    	rental.run();  // ** 수행자 수행 지시 **
    }
}

class Rental {
	
    public void run() {
    	// 도서 대여 프로세스 및 규칙
    }
}

수행자를 분리하면 명령 자체는 명령의 프로세스나 규칙에 구애받지 않게 된다.
명령은 그저 수행자의 호출을 지시하고,
명령에 세부 사항이 변경되면 수행하는 코드를 수정하면 된다.

커맨드 패턴은 명령을 객체화한 만큼, 명령의 변동성이 큰 부분이라고 할 수 있다.
명령을 중심으로 명령 외적으로는 그 종류와 수에 관계 없이 명령이 수행되고,
내부적으로는 프로세스나 규칙에 관계 없이 수행되도록 호출자와 수행자를 분리한 것이다!
명령의 추가와 수정이 유연하도록 설계한 것이 바로 커맨드 패턴이다.

이런 구조를 통해 유연함을 얻었을 뿐만 아니라,
핵심 로직의 개발(여기서는 도서 대출)에만 집중할 수 있는 환경이 구축됐다.

커맨드 패턴 단점

커맨드 패턴을 통해서 명령 추가가 간편해지고 수정이 매우 유연해졌다.
유연함과 동시에 수정해야 하는 명령이나 작업이 명확해져 관리가 수월해졌다.

하지만 모든 명령을 객체로 관리한다는 점에서 복잡성이 증가한다.
객체가 추가되었으니 명령 수행을 위해서는 객체도 생성해야 한다.

커맨드 패턴 도입 전과 후를 비교하면서 관리의 용이성 측면을 고려해보는 것이 좋겠다.

마무리

커맨드 패턴 도입 전에는 핵심 로직의 수정이 발생해 난감한 상황이었다.
비록 복잡성이 증가하지만 커맨드 패턴을 도입한 이후에는
작업의 Flow에 수정이 발생하지 않고, 구체적인 로직만 때에 따라 수정이 가능해졌다.
명령의 추가와 삭제도 용이해져 더욱 객체지향적인 설계가 가능해졌다.

특정 상황에 따라 대응하는 익숙한 구조가 발생한다면,
커맨드 패턴 구조를 떠올려 적절히 객체를 설계해보자.

profile
복습에 대한 비판과 지적을 부탁드립니다

0개의 댓글