Chain of Responsibility

2022. 3. 14. 00:00CSharp/Design Pattern

반응형

정의

일련의 핸들러를 따라 요청을 전달할 수 있는 행동 디자인 패턴

요청을 받으면 각 핸들러는 요청을 처리할지 아니면 체인의 다음 핸들러로 전달할지 결정

https://refactoring.guru/design-patterns/chain-of-responsibility

 

온라인 주문 시스템 있다고 가정하자.

 

1. 인증된 사용자만 주문을 생성한다.

2. 관리자는 모든 주문에 대한 액세스 권한이 있다.

 

https://refactoring.guru/design-patterns/chain-of-responsibility

 

시간이 흐른 후 몇가지를 추가 구현 하였다. 

 

3. 유효성 검사 단계를 추가

4. 동일한 IP 주소에서 오는 반복적으로 실패한 요청을 필터링 (무차별 암호 해독 문제 처리)

5. Caching ( performance 향상)

 

https://refactoring.guru/design-patterns/chain-of-responsibility

문제점

새로운 기능을 추가할 때마다 코드가 점점 많아짐.

하나의 검사를 변경 하면 다른 검사에 영향을 주기도 함.

일부 기능 (Aunthentication) 만 재사용 하려면 코드를 복사해 가야함.

 

이로인해 시스템을 이해하기가 매우 어렵고 유지 관리 비용이 많이 듬

 

 

해결책

각 검사를 단일 메서드를 사용하는 개별 클래스로 추출.

요청은 이 메세드에 데이타와 함께 인수로 전달.

이러한 핸들러를 체인으로 연결 하여 문제를 해결함

핸들러가 하나씩 줄 지어 체인을 형성

 

 

Class Diagram

사용

  • 다양한 방식으로 다양한 종류의 요청을 처리해야 하지만 요청 유형과 순서를 미리 알 수 없는 경우
  • 특정 순서로 여러 핸들러를 실행해야 하는 경우
  • 핸들러 세트와 해당 순서가 런타임에 변경되어야 하는 경우

 

아래와 같은 문제를 해결하는 코드를 만들어 보자

1... 10 까지의 숫자가 있고

 

첫번째는 3의 배수를 구하고

두번째는 앞에서 걸러진 숫자를 제외한 숫자들 중에서 짝수

세번째는 앞에서 걸러진 숫자를 제외한 숫자들 중에서 홀수

 

위와 같은 코드를 작성해 보자.

 

기본 인터페이스 및 Handler 정의

public interface IHandler
{
    void Next(IHandler handler);
    void Handle(int request);
}

public abstract class BaseHandler : IHandler
{
    protected IHandler? _handler;
    public abstract void Handle(int request);
    public void Next(IHandler handler) => _handler = handler;
    protected void Print(int request) => 
    	Console.WriteLine($"{GetType().Name} handled request {request}");
}

public class MultipleOfThreeHandler : BaseHandler
{
    public override void Handle(int request)
    {
        if (request % 3 == 0) Print(request);
        else _handler?.Handle(request);
    }
}

public class EvenHandler : BaseHandler
{
    public override void Handle(int request)
    {
        if (request % 2 == 0) Print(request);
        else _handler?.Handle(request);
    }
}

public class OddHandler : BaseHandler
{
    public override void Handle(int request)
    {
        if (request % 2 != 0) Print(request);
        else _handler?.Handle(request);
    }
}

사용법

IHandler h1 = new MultipleOfThreeHandler();
IHandler h2 = new EvenHandler();
IHandler h3 = new OddHandler();

h1.Next(h2);
h2.Next(h3);

var requests = Enumerable.Range(1,10) ;

foreach(var request in requests) h1.Handle(request);
//output
OddHandler handled request 1
EvenHandler handled request 2
MultipleOfThreeHandler handled request 3
EvenHandler handled request 4
OddHandler handled request 5
MultipleOfThreeHandler handled request 6
OddHandler handled request 7
EvenHandler handled request 8
MultipleOfThreeHandler handled request 9
EvenHandler handled request 10

 

관련영상

https://youtu.be/4xeQri027lc

 

 

반응형

'CSharp > Design Pattern' 카테고리의 다른 글

Memento  (0) 2022.03.16
Iterator  (0) 2022.03.15
Proxy  (0) 2022.03.11
Flyweight  (0) 2022.03.11
Facade  (0) 2022.03.10