C\#/.NET Core 에서 책임 체인 모드 를 사용 하 는 방법 을 자세히 설명 합 니 다.

10487 단어 C#책임 체인 모드
최근 에 제 친구 가 전형 적 인'Gang Of Four'디자인 모델 을 연구 하고 있 습 니 다.그 는 자주 나 에 게 실제 업무 응용 에서 어떤 디자인 모델 을 사 용 했 는 지 물 었 다.단일 모델,공장 모델,중개자 모델-모두 제 가 예전 에 사 용 했 고 심지어 관련 글 을 쓴 모델 입 니 다.그러나 한 가지 모델 은 내 가 아직 글 을 쓴 적 이 없다 는 것 이다.즉,책임 체인 모델 이다.
책임 체인 이 무엇 입 니까?\#
책임 체인 모드(이전에 나 는 명령 체인 모드 라 고 불 렀 다)는 레이 어 링 방식 으로'대상'을 처리 할 수 있 는 모델 이다.위 키 피 디 아 에서 의 전형 적 인 정 의 는?
대상 을 대상 으로 디자인 할 때 책임 체인 모델 은 명령 대상 소스 와 일련의 처리 대상 으로 구 성 된 디자인 모델 이다.모든 처리 대상 은 처리 할 수 있 는 명령 대상 의 논 리 를 포함 하고 나머지 는 체인 의 다음 처리 대상 에 게 전 달 됩 니 다.물론 새로운 처리 대상 을 체인 꼬리 에 추가 하 는 메커니즘 도 있다.따라서 책임 체인 은 If.else if.else if..else..endif 의 대상 지향 버 전 입 니 다.실행 할 때 동적 으로 다시 배열 하거나 조건 조작 블록 을 설정 할 수 있다 는 장점 이 있다.
아마도 위의 개념 묘사 가 너무 추상 적 이 고 이해 하기 어렵다 고 느 낄 것 이다.그러면 다음은 우리 가 실제 생활 속 의 예 를 살 펴 보 자.
여기 서 우리 가 은행 을 가지 고 있다 고 가정 하면 은행 안에 세 개의 등급 의 직원 이 있 는데 그것 이 바로'카운터 직원','주관','은행 매니저'이다.만약 누군가가 돈 을 찾 으 러 온다 면,카운터 직원 은 10,000 달러 이하 의 인출 조작 만 허용 한다.금액 이 10,000 달러 를 넘 으 면 그 요청 은'주관'에 게 전 달 될 것"이 라 고 말 했다."주관"은 100,000 달러 를 초과 하지 않 는 요 구 를 처리 할 수 있 지만 전 제 는 이 계좌 에 반드시 신분증 ID 가 있어 야 한 다 는 것 이다.신분증 ID 가 없 으 면 현재 요청 이 거부 되 어야 합 니 다.만약 에 인출 금액 이 100,000 달러 를 초과 하면 현재 의 요 구 는'은행 매니저'에 게 전달 할 수 있 고'은행 매니저'는 모든 인출 금액 을 비준 할 수 있다.만약 에 누군가가 100,000 달러 를 초과 하 는 금액 을 찾 으 면 그들 은 VIP 이기 때문에 우 리 는 VIP 의 신분증 ID 와 다른 규정 에 신경 쓰 지 않 는 다.
이것 이 바로 우리 가 앞에서 토론 한'체인'이다.모든 사람 이 현재 의 요 구 를 처리 하려 고 시도 하고 요 구 를 만족 시 키 지 못 하면 다음 에 전달 하 는 것 이다.만약 우리 가 이런 장면 을 코드 로 전환한다 면,바로 우리 가 말 한 책임 체인 모델 이다.하지만 그 전에 나 쁜 실현 방법 을 살 펴 보 자.
나 쁜 실현 방식\#
다음은 현재 문 제 를 해결 하기 위해 If/Else 블록 을 사용 합 니 다.

class BankAccount
{
  bool idOnRecord { get; set; }

  void WithdrawMoney(decimal amount)
  {
    //     
    if(amount < 10000)
    {
      Console.WriteLine("       ");
    } 
    //     
    else if (amount < 100000)
    {
      if(!idOnRecord)
      {
        throw new Exception("       ID");
      }

      Console.WriteLine("       ");
    }
    else
    {
      Console.WriteLine("         ");
    }
  }
}

상기 와 같은 실현 방식 에는 몇 가지 문제 가 있다.
IF/Else 코드 블록 이 너무 복잡 해 보이 기 때문에 새로운 직원 등급 을 추가 하 는 것 은 상당히 어 려 울 것 이다.
  • '주관'이 신분증 ID 를 검사 하 는 논 리 는 어느 정도 에 단원 테스트 를 하기 어렵다.왜냐하면 이것 은 반드시 다른 검 사 를 통과 해 야 하기 때문이다
  • 4.567917.지금 우 리 는 인출 금액 의 논리 만 정 의 했 지만 앞으로 우리 가 다른 검 사 를 추가 하려 면(예 를 들 어 VIP 고객 은 항상 주관 에 의 해 처리)이런 논 리 는 관리 하기 어렵 고 통 제 력 을 잃 기 쉽다책임 체인 모드 인 코딩 사용\#
    다음은 이 부분의 코드 를 다시 쓰 겠 습 니 다.이전 과 달리 우 리 는'직원'대상 을 만 들 었 고 그 안에 그들의 처리 논 리 를 봉인 했다.여기 서 가장 중요 한 것 은 우리 가 모든 직원 대상 에 게 직속 상급 자 를 지정 하여 그들 이 현재 의 요 구 를 처리 하지 못 할 때 직속 상급 에 게 요 구 를 전달 할 수 있 도록 해 야 한 다 는 것 이다.
    
    interface IBankEmployee
    {
      IBankEmployee LineManager { get; }
      void HandleWithdrawRequest(BankAccount account, decimal amount);
    }
    
    class Teller : IBankEmployee
    {
      public IBankEmployee LineManager { get; set; }
    
      public void HandleWithdrawRequest(BankAccount account, decimal amount)
      {
        if(amount > 10000)
        {
          LineManager.HandleWithdrawRequest(account, amount);
          return;
        }
    
        Console.WriteLine("       ");
      }
    }
    
    class Supervisor : IBankEmployee
    {
      public IBankEmployee LineManager { get; set; }
    
      public void HandleWithdrawRequest(BankAccount account, decimal amount)
      {
        if (amount > 100000)
        {
          LineManager.HandleWithdrawRequest(account, amount);
          return;
        }
    
        if(!account.idOnRecord)
        {
          throw new Exception("       ID");
        }
    
        Console.WriteLine("       ");
      }
    }
    
    class BankManager : IBankEmployee
    {
      public IBankEmployee LineManager { get; set; }
    
      public void HandleWithdrawRequest(BankAccount account, decimal amount)
      {
        Console.WriteLine("         ");
      }
    }
    
    
    우 리 는 상급 자 를 지정 하 는 방식 으로 책임 체인 을 만 들 수 있다.이것 은 보기에 조직 구조 도 같다.
    
    var bankManager = new BankManager();
    var bankSupervisor = new Supervisor { LineManager = bankManager };
    var frontLineStaff = new Teller { LineManager = bankSupervisor };
    
    여기 서 우 리 는 BankAccount 류 를 만 들 고 인출 방법 을 프런트 직원 으로 전환 하여 처리 할 수 있다.
    
    class BankAccount
    {
      public bool idOnRecord { get; set; }
    
      public void WithdrawMoney(IBankEmployee frontLineStaff, decimal amount)
      {
         frontLineStaff.HandleWithdrawRequest(this, amount);
      }
    }
    
    
    지금 우리 가 인출 요 구 를 할 때'카운터'는 항상 제일 먼저 처리 하고 처리 하지 못 하면 자동 으로 직속 지도자 에 게 요 구 를 보 낼 것 이다.이런 모델 의 우아 함 은 다음 과 같은 몇 가지 가 있다.
    4.567917.체인 의 후속 부분 항목 은 어떤 부분 이 명령 을 전달 하 는 지 알 필요 가 없다.여기 처럼'주관'은 왜 하급'카운터'가 왜 그 에 게 청 구 를 전 달 했 는 지 알 필요 가 없다.
    4.567917.'카운터 맨'은 전체 체인 을 알 필요 가 없다.그 는 단지 요청 을 상급자 에 게 전달 하 는 것 을 책임 지고,요청 이 상급자 의'주관'에 게 처 리 될 수 있 기 를 기대한다(현재 더 많은 전달 처리 가 필요 할 지도 모른다)4.567917.신 입 사원 유형 을 도입 할 때 전체 조직 구조 도 는 쉽게 변경 된다.예 를 들 어 나 는 새로운'카운터 매니저'역할 을 만 들 었 다.그 는 10,000-50,000 달러 간 의 인출 요 구 를 처리 할 수 있 고'카운터 매니저'의 직속 상급 자 는'주관'이다.여기 서 우 리 는'주관'대상 에 대해 어떠한 처리 도 할 필요 가 없다.'카운터'의 직속 상급 자 를'카운터 매니저'로 바 꾸 면 된다4.567917.단원 테스트 를 작성 할 때 우 리 는 한 번 에 한 명의 직원 역할 에 만 관심 을 가 질 수 있 습 니 다.예 를 들 어'주관'논 리 를 테스트 할 때 우 리 는'카운터'의 논 리 를 테스트 할 필요 가 없다확장 우리 의 예\#
    비록 나 는 이상 의 예 가 이러한 모델 을 잘 설명 할 수 있다 고 생각 하지만,일반적으로 어떤 사람들 은 SetNext 라 는 방법 을 사용 하 는 것 을 발견 할 수 있다.일반적으로 나 는 이것 이 C\#에서 매우 보기 드 문 것 이 라 고 생각한다.왜냐하면 C\#에서 우 리 는 속성 획득 기와 설정 기 를 사용 할 수 있 기 때문이다.SetVariableName 방법 을 사용 하 는 것 은 보통 C++시대 의 일 입 니 다.그 때 는 변 수 를 봉인 하 는 가장 좋 은 방법 입 니 다.
    그러나 여기 서 가장 중요 한 것 은 다른 예 는 추상 류 를 사용 하여 전달 을 요청 하 는 방식 을 강화 하 는 것 이다.앞의 코드 중 하 나 는 다음 프로세서 에 요청 을 전달 할 때 중복 코드 를 많이 만 들 었 다 는 것 입 니 다.그럼 코드 를 정리 해 봅 시다.
    여기 서 우리 가 해 야 할 첫 번 째 일 은 바로 추상 류 를 만 드 는 것 이다.이 추상 류 는 우리 로 하여 금 표준화 된 방식 으로 인출 요 구 를 처리 할 수 있 게 한다.조건 이 충족 되면 인출 을 집행 하고,반대로 직속 상급자 에 게 요청 을 전달 하 는 검사 조건 을 정의 해 야 한다.수 정 된 코드 는 다음 과 같 습 니 다.
    
    interface IBankEmployee
    {
      IBankEmployee LineManager { get; }
      void HandleWithdrawRequest(BankAccount account, decimal amount);
    }
    
    abstract class BankEmployee : IBankEmployee
    {
      public IBankEmployee LineManager { get; private set; }
    
      public void SetLineManager(IBankEmployee lineManager)
      {
        this.LineManager = lineManager;
      }
    
      public void HandleWithdrawRequest(BankAccount account, decimal amount)
      {
        if (CanHandleRequest(account, amount))
        {
          Withdraw(account, amount);
        } 
        else
        {
          LineManager.HandleWithdrawRequest(account, amount);
        }
      }
    
      abstract protected bool CanHandleRequest(BankAccount account, decimal amount);
    
      abstract protected void Withdraw(BankAccount account, decimal amount);
    }
    
    
    다음 단계 에 우 리 는 모든 직원 류 를 수정 하여 BankEmployee 추상 류 에서 계승 하도록 해 야 한다.
    
    class Teller : BankEmployee, IBankEmployee
    {
      protected override bool CanHandleRequest(BankAccount account, decimal amount)
      {
        if (amount > 10000)
        {
          return false;
        }
        return true;
      }
    
      protected override void Withdraw(BankAccount account, decimal amount)
      {
        Console.WriteLine("       ");
      }
    }
    
    class Supervisor : BankEmployee, IBankEmployee
    {
      protected override bool CanHandleRequest(BankAccount account, decimal amount)
      {
        if (amount > 100000)
        {
          return false;
        }
        return true;
      }
    
      protected override void Withdraw(BankAccount account, decimal amount)
      {
        if (!account.idOnRecord)
        {
          throw new Exception("       ID");
        }
    
        Console.WriteLine("       ");
      }
    }
    
    class BankManager : BankEmployee, IBankEmployee
    {
      protected override bool CanHandleRequest(BankAccount account, decimal amount)
      {
        return true;
      }
    
      protected override void Withdraw(BankAccount account, decimal amount)
      {
        Console.WriteLine("         ");
      }
    }
    
    
    모든 장면 에서 추상 클래스 의 Handle Witdraw Request 공공 방법 을 사용 합 니 다.이 방법 은 하위 클래스 에서 정의 하 는 CanHandleRequest 방법 을 호출 하여 현재 캐릭터 가 처리 요청 조건 을 충족 하 는 지 확인 하고,만족 하면 하위 클래스 의 With draw 방법 으로 요청 을 처리 합 니 다.그렇지 않 으 면 요청 을 상위 캐릭터 에 게 전달 하려 고 시도 합 니 다.
    우 리 는 다음 코드 처럼 직원 체인 을 만 드 는 방식 을 바 꾸 면 됩 니 다.
    
    var bankManager = new BankManager();
    
    var bankSupervisor = new Supervisor();
    bankSupervisor.SetLineManager(bankManager);
    
    var frontLineStaff = new Teller();
    frontLineStaff.SetLineManager(bankSupervisor);
    여기 서 다시 한 번 말씀 드 리 지만 저 는 SetXXX 라 는 방법 을 사용 하 는 것 을 좋아 하지 않 습 니 다.그러나 많은 예 에서 이렇게 사용 하 는 것 을 좋아 하기 때문에 저 는 그것 을 추 가 했 습 니 다.
    일부 예 에서 도 직원 들 이 처리 요 구 를 만족 시 키 는 지 판단 하 는 조건 을 추상 류 에 둔다.나 는 개인 적 으로 이렇게 하 는 것 을 좋아 하지 않 는 다.왜냐하면 이것 은 모든 처리 프로그램 이 비슷 한 논 리 를 사용 해 야 한 다 는 것 을 의미 하기 때문이다.예 를 들 어 현재 의 모든 검 사 는 추출 금액 에 기반 을 두 고 있 지만 만약 에 우리 가 특수 한 처리 절 차 를 실현 하려 면 그 조건 이 VIP 표지 와 관련 이 있다 면 우 리 는 추상 적 인 유형 에서 IF/Else 를 다시 사용 해 야 한다.이것 은 우 리 를 IF/Else 의 감옥 으로 데려 갈 것 이다.
    책임 체인 모드 는 언제 사용 해 야 합 니까?\#
    이런 모델 의 가장 좋 은 사용 장면 은 당신 의 업무 에 논리 적 인 처리 체인 이 있 는데 이 처리 체인 은 매번 순서대로 운행 해 야 한 다 는 것 이다.여기 서 체인 의 갈 라 지 는 것 은 이런 모델 의 변형 이지 만 곧 처리 하면 매우 복잡 할 것 이라는 것 을 주의 하 세 요.그래서 제 가 현실 세계 에서'명령 체인'장면 을 모델 링 할 때 저 는 이런 모델 을 자주 사용 합 니 다.이것 이 바로 내 가 은행 을 예 로 들 수 있 는 이유 이다.왜냐하면 그것 이 바로 현실 세계 에서 코드 로 모델 링 을 할 수 있 는'책임 체인'이기 때문이다.
    C\#/.NET Core 에서 책임 체인 모드 를 사용 하 는 방법 에 대한 자세 한 설명 은 여기까지 입 니 다.더 많은 C\#/.NET Core 책임 체인 모드 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 부탁드립니다!
    원문
    저자:웨 이 드
    Lamond Lu
    출처:Chain Of Responsbility Pattern In C#/.NET Core
    저작권:본 고 는'서명 4.0 국제'지식 공유 허가 협 의 를 이용 하여 허 가 를 한다.

    좋은 웹페이지 즐겨찾기