커맨드 패턴
커맨드 패턴
요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있다.
이러면 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있다.
명령을 추상화해서 객체로 사용한다.
클라이언트에서 커맨드 객체 생성
커맨드 객체에는 행동과 리시버(receiver)의 정보가 같이 들어있음
커맨드 객체에서 제공하는 메소드는
excute()
하나뿐행동을 캡슐화하며 리시버에 있는 특정 행동을 처리한다.
인보커(invoker) 객체의
setCommand()
메서드에 커맨드 객체를 넘겨서 호출넘긴 커맨드객체를 사용하기 전까지 인보커 객체에서 보관
ex:
remoteControl.setCommand(0, partyOnMacro, partyOffMacro)
인보커에서 커맨드 객체의
excute()
메서드 호출리시버에 있는 행동 메서드가 호출됨
키워드
인보커(Invoker): 명령이 들어있으며,
execute()
메서드를 호출함으로써 커맨드 객체에게 특정 작업을 수행하도록 요청작업 요구 담당 (종업원)
setCommand
커맨드(Command): 커맨드 객체에서 구현해야 하는 인터페이스,
execute: 리시버에 특정 작업을 처리하라는 지시를 전달
undo: 작업 취소
리시버(Receiver): 요구사항을 수행할 때 어떤일을 처리해야 하는지 알고 있는 객체
작업 처리 담당 (주방장)
action
커맨드 객체(ConcreteCommand): 특정 행동과 리시버를 연결해줌
주문서
execute: 리시버에 있는 메서드를 호출해서 요청된 작업을 처리
undo: 실행했던 작업을 원복 on <--> off
핵심 정리
커맨드 패턴을 사용하면 요청하는 객체와 요청을 수행하는 객체를 분리 가능
분리하는 과정에 중심에는 커맨드 객체가 있고, 행동이 들어있는 리시버를 캡슐화함
인보커는 무언가 요청할 때 커맨드 객체의
execute()
메서드를 호출하면 됨커맨드는 인보커를 매개변수화할 수 있음
실행 중에 동적으로 매개변수화를 설정할 수도 있음
execute()
메서드가 마지막으로 호출되기 전의 상태로 되돌리는 작업 취소 메서드를 구현하면 커맨드 패턴으로 작업 취소 기능을 구현 가능매크로 커맨드는 커맨드를 확장해서 여러 커맨드를 한 번에 호출할 수 있게 해주는 가장 간편한 방법
요청을 스스로 처리하는 '스마트;커맨드 객체를 사용하는 경우도 종종 있음
커맨드 패턴을 활용해서 로그 및 트랜잭션 시스템을 구현할 수도 있음
커맨드 객체 만들기
커맨드 객체는 모두 같은 인터페이스를 구현해야 함
오직
excute()
메서드를 하나만 갖고 있음
커맨드 객체를 사용해서 리모콘 만들기
NoCommand 객체
커맨드 인터페이스에 따르고 excute() 실행시 아무 동작도 하지 않는 커맨드 객체
일종의 널 객체
딱히 리턴할 객체도 없고 클라이언트가 null을 처리하지 않게 하고 싶을 때 활용
명령이 아직 할당되지 않는 부분에 NoCommand 객체를 넣어서 execute()가 호출되어도 문제가 생기지 않도록
작업 취소 기능 추가하기
마지막으로 실행된 명령을 기록하는 인스턴스 변수를 추가
Undo 실행시 기록해 뒀던 커맨드 객체 레퍼런스로 undo() 메서드 호출
여러 동작을 한 번에 처리하기
다른 커맨드를 실행할 수 있는 새로운 종류의 커맨드 객체를 만들어 여러 커맨드를 한번에 실행
항상 리시버가 필요한지? 커맨드 객체에서 직접 execute() 로직을 구현하면 안되나?
일반적으로는 리시버에 있는 행동을 호출하는 '더미' 커맨드 객체를 만든다.
물론 커맨드 객체에서 대부분의 행동을 처리해도 되지만
인보커와 리시버를 분리하기 어려워짐
리시버로 커맨드를 매개변수화할 수 없어짐
커맨드로 컴퓨티에이션(computation)의 한 부분(리시버와 일련의 행동)을 패키지로 묶어 일급 객체 형태로 전달할 수도 있다.
커맨드 객체를 생성한 뒤 오랜 시간이 지나도 그 컴퓨테이션을 호출 가능
심지어 다른 스레드에서도 호출 가능
이점을 활용해 커맨드 패턴을 활용하여 스케줄러, 스레드 풀, 작업 큐와 같은 다양한 작업에 적용함
Last updated