본문 바로가기
디자인 패턴

GoF 행동 패턴 소개 (1)

by oncerun 2022. 11. 15.
반응형

빠르게 훑고 책으로 보충하자!

 

행동 패턴은 객체 간의 효과적인 의사소통과 책임 할당을 처리한다. 

 

책임 연쇄 패턴

 

책임 연쇄 패턴은 핸들러들의 체인을 따라 요청을 전달할 수 있게 해주는 패턴으로 Spring security에서 이와 같은 패턴을 찾아볼 수 있다. 각 핸들러는 요청을 받으면 해당 요청을 처리할지 아니면 다음 핸들러로 넘길지 결정할 수 있습니다.

 

 

1. 핸들러는 모든 핸들러에 공통적인 인터페이스를 선언한다.  이 인터페이스는 요청을 처리하기 위한 메서드와 다음 핸들러로 책임을 넘기는 메서드가 공통될 수 있다.

 

2. BaseHandler는 공통 처리 부분에 대한 핸들러이다.

 

3. 실제 구상 핸들러는 요청을 처리하기 위한 실제 코드가 포함되어 있으며 각 핸들러는 요청을 처리할지와 체인으로 넘길지 결정한다. 

 

책임 연쇄 패턴은 다양한 방식으로 다양한 종류의 요청들을 처리할 것으로 예상되지만 정확한 요청 유형들과 순서들을 알 수 없는 경우에 사용하라 권한다.

 

이는 각 핸들러들에게 이 요청을 처리할 수 있는지 묻기 때문에 각 핸들러가 요청을 처리할 기회를 얻을 수 있다. 

 

책임 연쇄 패턴은 핸들러들을 정적으로 구성할 수도 있지만 런타임에 동적으로 변경할 수 도 있다. 

 

하나의 흐름에 여러 책임들이 덕지덕지 붙어야 하고 해당 순서를 런타임에도 조절하고 싶을 때 사용하면 될 것 같다. 

 

단일 책임 원칙을 지키면서 요청의 처리 순서를 제어할 수 있다는 점. 클라이언트 코드를 손대지 않고 핸들러들을 추가/삭제/변경할 수 있다는 개방/폐쇄 원칙이 적용된다는 점이 장점이라 할 수 있겠다.

 

 

커맨드 패턴

 

- 요청 자체를 캡슐화하여 호출자와 수신자를 분리하는 패턴

 

관심사 분리의 원칙을 기반으로 생각해보자.

 

요청자가 모든 정보를 알고 수신자에게 전달한다. 

 

커맨드 패턴은 이러한 요청을 직접 전달해서는 안된다고 한다. 대신 모든 요청의 세부 정보들인 호출 객체, 메서드, 인수 리스트 등.. 요청을 작동시키는 단일 메서드를 가진 별도의 커맨드 클래스로 추출하라고 권고한다.

 

요청에 대한 모든 정보를 가진 객체를 만들어야 한다고 한다.  일반적으로 커맨드는 매개 변수들을 받지 않는 단일 실행 메서드만을 가진다. 이는 Runnable과 되게 비슷한 구조를 가졌다. 

 

 요청자가 수신자에게 전달할 메서드를 정의한 인터페이스를 만들고 커맨드는 해당 인터페이스를 구현한다.

 

일단 이로서 요청자는 커맨드의 코드 변경으로부터 영향을 받지 않게 된다.  중간의 링크 역할을 하는 커맨드 인터페이스가 생겼기 때문이다.  이로써 런타임에 호출자의 행동을 변경할 수 도있다.

 

위에서 커맨드는 매개 변수들을 받지 않는 단일 실행 메서드만을 가진다고 했다. 

하지만 생각해보면 호출자 입장에서는 수신자에게 매개변수를 넘겨줘야 하기도 한다. 

 

아니? 매개변수가 없다니? 이 요청의 세부 정보를 수신자에게 어떻게 전달하지?

 

바로 링크역할을 하는 인터페이스를 구현한 커맨드 클래스 내부 속성에 해당 요청 정보를 미리 설정하거나 자체적으로 가져올 수 있도록 구성하는 것입니다. 

 

이를 위해선 요청 정보를 별도의 enum으로 처리할 수 있다면 만들어도 될듯합니다. 

 

그러면 해당 요청 정보(커맨드)를 재활용한다고 해도 같은 관심사가 아닌 경우에는 커맨드는 증가할 수밖에 없을 것입니다.

 

다시 한번 이해해보자. 

 

현실에서 업무를 노션, 슬랙과 같은 공간에 동일한 인터페이스 형식으로 할당받는다고 하자. 이 업무가 담겨있는 공간은 일종의 커맨드 역할을 한다. 

 

이 업무를 실제 진행하기까지 해당 업무는 업무 리스트 공간에서 대기를 하고 그 공간에는 업무에 대한 요청사항과 같은 모든 관련 정보가 포함되어 있다. 

직접 상사에게 업무를 전달받는 대신 업무 관련 정보와 업무 내용이 들어있는 공간을 보고 바로 업무를 시작할 수 있다. 

 

아직 이해가 잘 되지 않는다 구조를 하나씩 살펴보자.

1. Invoker

 

Invoker 호출자를 뜻한다. 이는 요청을 시작하는 역할이다. 

호출자를 느커맨드 객체에 대한 참조를 저장하기 위한 필드가 있어야 한다. 

Receiver, 수신자에게 요청을 직접 보내는 대신 해당 커맨드를 작동시킨다. 

 

* 호출자는 커맨드를 생성할 책임이 없으며 일반적으로 생성자를 통해 클라이언트로부터 미리 생성된 커맨드를 받는다. 

 

2. Command <<Interface>>

 

커맨드를 실행하기 위한 인자 없는 단일 메서드만을 선언

 

3. Concrete Command

 

다양한 유형의 요청을 구현한다. 이러한 구현체 커맨드는 자체적으로 작업을 수행해서는 안 되며, 비즈니스 논리 객체 중 하나에 호출을 전달해야 한다.

 

즉 실제 수신자에게 전달하는 것이 목적이며, 수신자가 메서드를 실행하는 데 필요한 매개변수들은 구현체 커맨드의 필드들로 선언할 수 있다. 불변으로 만들고 싶다면 필드들의 초기화를 이용해도 된다.

 

4. Receiver

 

수신자는 비즈니스 로직이 포함되어 있습니다. 대부분 커맨드들은 요청이 수신자에게 전달되는 방법에 대한 세부 정보만 처리하는 반면 수신자 자체는 실제 작업을 수행한다. 

 

5. Client

클라이언트는 구현체 커맨드 객체들을 만들고 설정한다. DI 프레임워크를 적용한다고 생각해보자. 

이때 수신자 인스턴스를 포함한 모든 요청 매개변수들을 커맨드의 생성자로 전달해야 하며, 그렇게 만들어진 커맨드는 하나 또는 여러 호출자와 연관될 수 있다. 

 

DI를 할 때 수신자 인스턴스를 같이 전달할 수는 있겠지만 모든 요청 매개변수들을 생성자로 전달할 수 있을까?

 

이는 작업들로 객체를 매개변수 화하려는 경우 커맨드 패턴을 사용하라 권고한다. 

 

커맨드 패턴은 특정 메서드 호출을 독립실행형 객체로 전환할 수 있다. 이 변경을 통해 커맨드들을 메서드 인수로 전달하고 다른 객체들의 내부에 저장하고, 런타임에 커맨드를 변경할 수 있다.

 

또 작업들의 실행을 예약하거나, 대기열에 넣거나, 원격으로 실행하려는 경우 사용하라 한다. 

커맨드는 객체이기 때문에 직렬화될 수 있고 이는 복원되어 지연 실행할 수 있음을 의미한다. 

 

되돌릴 수 있는 작업을  구현하려고 할 때 사용해라. 

실행 취소/ 다시 실행을 구현하는 방법에는 여러 가지가 있지만, 커맨드 패턴이 아마 가장 많이 사용되는 패턴이라고 합니다. 

 

작업을 되돌리려면 수행한 작업의 기록을 구현해야 한다. 

 

구현은 어떻게 하면 좋을까?

 

1. 함수형 인터페이스로 커맨드 인터페이스 선언

2. 요청들을 커맨드 인터페이스를 구현하는 구현체로 추출하기 시작하고, 각 클래스에는 실제 수신자 객체에 대한 참조와 요청 인수들을 저장하기 위한 필드들의 집합이 있어야 하고 이러한 모든 값은 커맨드의 생성자를 통해 초기화되어야 한다.

3. 호출자 역할을 할 클래스를 식별하자. 이러한 클래스들에 커맨드들을 저장하기 위한 필드가 필요하다. 

이후 커맨드 인터페이스를 통해서만 커맨드들과 통신해야 한다.  보통 호출자들은 클라이언트 코드에서 주입받는다.

4. 수신자에게 직접 요청을 보내는 대신 커맨드를 실행하도록 호출자 코드를 변경해라

5. 클라이언트는 수신자를 만들고, 커맨드들을 만들고 필요한 경우 수신자들과 연관시키자. 호출자를 만들고 특정 커맨드와 연관시키자.

 

공부할 수 록 전략 패턴과 뭐가 다른지 잘 이해가 되지 않는다. 

 

이 둘의 의도는 뭐가 다를까?

 

커맨드 패턴은  요청을 캡슐화한다. 이를 통해 지연 로딩, 대기열을 통한 undo작업, 매개변수 필드 화가 가능하다.

전략 패턴은 일반적으로 같은 작업을 하는 다양한 방법을 이야기하는데, 단일 콘테스트 클래스 안에서 이러한 알고리즘이 교환될 수 있도록 하는 것.

 

 

전략 패턴

 

어떤 일을 수행하는 방법이 여러 가지일 때 여러 알고리즘을 각각 클래스로 캡슐화를 하고 그 캡슐화된 걸 공통화된 인터페이스로 추상화해서 로직 수행하는 부분에서 사용하는 것. 

여러 알고리듬을 쉽게 바꿔낄 수 있는 것...

 

 

반응형

'디자인 패턴' 카테고리의 다른 글

Gof 행동 디자인 패턴 : State  (0) 2022.11.20
Gof 생성 디자인 패턴 : Builder  (0) 2022.11.19
GoF 구조적인 패턴 소개  (0) 2022.11.06
책임 연쇄 패턴 +[F]  (0) 2022.02.19
데코레이터 패턴 + [F]  (0) 2022.02.19

댓글