2010-04-14 9 views
5

제 이해를 돕기 위해 Chain-Of-Responance 패턴을 구현했습니다. 체인-의 책임을 깨지 않고C# 대리인의 책임 체인

질문

//Abstract Base Type 

public abstract class CustomerServiceDesk 
{ 
protected CustomerServiceDesk _nextHandler; 
public abstract void ServeCustomers(Customer _customer); 
public void SetupHadler(CustomerServiceDesk _nextHandler) 
{ 
      this._nextHandler = _nextHandler; 
} 
} 

public class FrontLineServiceDesk:CustomerServiceDesk 
{ 
    public override void ServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.General) 
     { 
      Console.WriteLine(_customer.Name + " Complaints are registered ; 
      will be served soon by FrontLine Help Desk.."); 
     } 

     else 
     { 
      Console.WriteLine(_customer.Name + " 
      is redirected to Critical Help Desk"); 

      _nextHandler.ServeCustomers(_customer); 
     } 

     } 
    } 
public class CriticalIssueServiceDesk:CustomerServiceDesk 
{ 
    public override void ServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.Critical) 
     { 
      Console.WriteLine(_customer.Name + 
      "Complaints are registered ; will be served soon 
      by Critical Help Desk"); 
     } 
     else if (_customer.ComplaintType == ComplaintType.Legal) 
     { 
      Console.WriteLine(_customer.Name + 
      "is redirected to Legal Help Desk"); 
      _nextHandler.ServeCustomers(_customer); 
     } 
    } 
} 

public class LegalissueServiceDesk :CustomerServiceDesk 
{ 
    public override void ServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.Legal) 
     { 
      Console.WriteLine(_customer.Name + 
      "Complaints are registered ; 
      will be served soon by legal help desk"); 
     } 
    } 
} 


public class Customer 
{ 
    public string Name { get; set; } 
    public ComplaintType ComplaintType { get; set; } 
} 


public enum ComplaintType 
{ 
    General, 
    Critical, 
    Legal 
} 

void Main() 
{ 
CustomerServiceDesk _frontLineDesk = new FrontLineServiceDesk(); 
CustomerServiceDesk _criticalSupportDesk = new CriticalIssueServiceDesk(); 
CustomerServiceDesk _legalSupportDesk = new LegalissueServiceDesk(); 
_frontLineDesk.SetupHadler(_criticalSupportDesk); 
_criticalSupportDesk.SetupHadler(_legalSupportDesk); 

Customer _customer1 = new Customer(); 
_customer1.Name = "Microsoft"; 
_customer1.ComplaintType = ComplaintType.General; 

Customer _customer2 = new Customer(); 
_customer2.Name = "SunSystems"; 
_customer2.ComplaintType = ComplaintType.Critical; 

Customer _customer3 = new Customer(); 
_customer3.Name = "HP"; 
_customer3.ComplaintType = ComplaintType.Legal; 

_frontLineDesk.ServeCustomers(_customer1); 
_frontLineDesk.ServeCustomers(_customer2); 
_frontLineDesk.ServeCustomers(_customer3); 
} 

은, 내가 어떻게 코드를 다시 작성하는 대의원 및 이벤트를 적용 할 수 있는가? 내가 제대로 이해하면

답변

7

은 ... 당신이 할 수있는 것은 SetupHandler 방법을 제거하고 CriticalHelpDesk 객체가 FrontLineHelpDesk.OnElevateQuery 이벤트를 처리 할 수있는 당신의 LegalHelpDesk 객체가 CriticalHelpDesk.OnElevateQuery 이벤트를 처리 할 수 ​​않던 OnElevateQuery 이벤트를 소개합니다. OnElevateQuery 이벤트는 이벤트 인수로 고객을 전달할 수 있습니다.

CustomerServiceDesk _frontLine = new FrontLineServiceDesk(); 
CustomerServiceDesk _criticalLine = new CriticalLineServiceDesk(); 
CustomerServiceDesk _legalLine = new LegalLineServiceDesk(); 
// hook up events 
_frontLine.OnElevateQuery += _critialLine.ServeCustomer; 
_criticalLine.OnElevateQuery += _legalLine.ServeCustomer; 

Customer _customer1 = new Customer(); 
_customer1.Name = "Microsoft"; 
_customer1.ComplaintType = ComplaintType.General; 

Customer _customer2 = new Customer(); 
_customer2.Name = "SunSystems"; 
_customer2.ComplaintType = ComplaintType.Critical; 

Customer _customer3 = new Customer(); 
_customer3.Name = "HP"; 
_customer3.ComplaintType = ComplaintType.Legal; 

_frontLine.ServeCustomer(_customer1); 
_frontLine.ServeCustomer(_customer2); 
_frontLine.ServeCustomer(_customer3); 

그러나

public abstract class CustomerServiceDesk 
{ 
    public delegate void ElevateQueryEventHandler(Customer c); 
    public event ElevateQueryEventHandler OnElevateQuery; 
    public abstract void ServeCustomer(Customer c); 
} 

public class FrontLineServiceDesk : CustomerServiceDesk 
{ 
    public override void ServeCustomer(Customer c) 
    { 
     switch (c.ComplaintType) 
     { 
      case ComplaintType.General: 
       Console.WriteLine(c.Name + " Complaints are registered; will be served soon by FrontLine Help Desk"); 
       break; 
      default: 
       OnElevateQuery(c); 
     } 
    } 
} 

public class CriticalIssueServiceDesk : CustomerServiceDesk 
{ 
    public override void ServeCustomer(Customer c) 
    { 
     switch (c.ComplaintType) 
     { 
      case ComplaintType.Critical: 
       Console.WriteLine(c.Name + " Complaints are registered; will be served soon by Critical Help Desk"); 
       break; 
      case ComplaintType.Legal: 
       OnElevateQuery(c); 
       break; 
      default: 
       Console.WriteLine("Unable to find appropriate help desk for your complaint."); 
       break; 
     } 
    } 
} 

public class LegalIssueServiceDesk : CustomerServiceDesk 
{ 
    public override void ServeCustomer(Customer c) 
    { 
     if (c.CompliantType == CompliantType.Legal) 
     { 
      Console.WriteLine(c.Name + " Complaints are registered; will be served soon by Legal Help Desk"); 
     } 
     else 
     { 
      // you could even hook up the FrontLine.ServeCustomer event 
      // to the OnElevateQuery event of this one so it takes the 
      // query back to the start of the chain (if it accidently ended up here). 
      Console.WriteLine("Wrong department"); 
     } 
    } 
} 

사용 쿼리 유형을 열거 ComplaintType을 기반으로, 당신은 예를 들어, 일반적인 인터페이스를 반환 할 수있는 아마 HelpDeskFactory를 사용하여 고려가 IHelpDesk. 이 특정 사례에 대해서는 전략 패턴을 사용할 수도 있습니다.

+0

우수 설명, HelpDeskFactory를 제안 해 주셔서 감사합니다. – user274364

+0

@nettguy : 문제 없음 :) – James

2

complaintType이있는 고객은 잘못 배치 된 속성처럼 보입니다. 불만 사항이 유형이라는 것을 의미하는 것으로 간주합니다.

내가 잘못했을 수 있습니다 어떤 동작이 없는지 가리킬 수 있습니다 이것은 내게 이벤트처럼 보입니다. 각 이벤트 핸들러는 구독 순서대로 호출됩니다. 각 처리자는 불만 사항에 따라 통보를 무시할 수 있습니다. 다음 처리기는 eventArgs의 Handled 속성이 false이고 보류중인 구독자가있는 한 호출됩니다.

class ComplaintSource 
{ 
    public delegate void ComplaintHandler(Complaint complaint, HandledEventArgs evtArgs); 
    public event ComplaintHandler NewComplaint; 

    // code that raises the NewComplaint event as appropriate. 
    public void DoStuffThatRaisesTheEvent() 
    { 
     var evtArgs = new HandledEventArgs(); 
     var theComplaint = new Complaint(); 
     if (null == this.NewComplaint) 
      return; 

     Delegate[] list = NewComplaint.GetInvocationList(); 
     foreach (Delegate del in list) 
     { 
      if (evtArgs.Handled) 
       break; 
      ComplaintHandler handler = (ComplaintHandler)del; 
      handler(theComplaint, evtArgs); 
     } 
    } 
} 

class FrontLineServiceDesk 
{ 
    FrontLineServiceDesk(ComplaintSource source) 
    { source.NewComplaint += HandleGeneralComplaint; } 
    void HandleGeneralComplaint(Complaint complaint, HandledEventArgs evtArgs) { ... 
    // set evtArgs.Handled = true if you've handled the complaint 
    // this will stop the chain 
    } 
} 

class CriticalIssueServiceDesk 
{ 
    CriticalIssueServiceDesk(ComplaintSource source) 
    { source.NewComplaint += HandleGeneralComplaint; } 
    void HandleCriticalComplaint(Complaint complaint, HandledEventArgs evtArgs) { ... } 
} 

// finally set the ball in motion 

var source = new CompaintSource(); 
var frontLineDesk = new FrontLineServiceDesk(source); 
var criticalIssueDesk = new CriticalIssueServiceDesk(source); 

source.DoStuffThatRaisesTheEvent(); 
+3

그는 책임 직무를 이해하려고 노력하고 최선을 다해 코드를 작성하지 않습니다. –

+0

@ Gishu 대단히 감사합니다. – user274364

-1

위의 답변과 매우 유사하지만보다 간소화되었습니다. :)

public abstract class CustomerServiceDesk 
{ 
    protected CustomerServiceDesk() 
    { 
     ServeCustomers = doServeCustomers; 
    } 

    protected CustomerServiceDesk m_ServiceDesk = null; 
    protected abstract void doServeCustomers(Customer _customer); 

    public delegate void ServeCustomersDelegate(Customer _customer); 
    public ServeCustomersDelegate ServeCustomers = null; 
} 

public class LegalissueServiceDesk : CustomerServiceDesk 
{ 
    public LegalissueServiceDesk() 
    { 
    } 

    protected override void doServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.Legal) 
     { 
      Console.WriteLine(_customer.Name + " - Complaints are registered ; will be served soon by legal help desk.\n"); 
     } 
    } 
} 

public class CriticalIssueServiceDesk : CustomerServiceDesk 
{ 
    public CriticalIssueServiceDesk() 
    { 
     m_ServiceDesk = new LegalissueServiceDesk(); 
     ServeCustomers += m_ServiceDesk.ServeCustomers; 
    } 

    protected override void doServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.Critical) 
     { 
      Console.WriteLine(_customer.Name + " - Complaints are registered ; will be served soon by Critical Help Desk.\n"); 
     } 
    } 
} 

public class FrontLineServiceDesk : CustomerServiceDesk 
{ 
    public FrontLineServiceDesk() 
    { 
     m_ServiceDesk = new CriticalIssueServiceDesk(); 
     ServeCustomers += m_ServiceDesk.ServeCustomers; 
    } 

    protected override void doServeCustomers(Customer _customer) 
    { 
     if (_customer.ComplaintType == ComplaintType.General) 
     { 
      Console.WriteLine(_customer.Name + " - Complaints are registered ; will be served soon by FrontLine Help Desk.\n"); 
     } 
    } 
} 

public class Customer 
{ 
    public string Name; 
    public ComplaintType ComplaintType; 
} 

public enum ComplaintType 
{ 
    General, 
    Critical, 
    Legal 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Customer _customer1 = new Customer(); 
     _customer1.Name = "Microsoft"; 
     _customer1.ComplaintType = ComplaintType.General; 

     Customer _customer2 = new Customer(); 
     _customer2.Name = "SunSystems"; 
     _customer2.ComplaintType = ComplaintType.Critical; 

     Customer _customer3 = new Customer(); 
     _customer3.Name = "HP"; 
     _customer3.ComplaintType = ComplaintType.Legal; 

     FrontLineServiceDesk _frontLineDesk = new FrontLineServiceDesk(); 

     _frontLineDesk.ServeCustomers(_customer1); 
     _frontLineDesk.ServeCustomers(_customer2); 
     _frontLineDesk.ServeCustomers(_customer3); 

     Console.In.ReadLine(); 
    } 
} 
+0

유선형 버전이 나머지 버전보다 길다는 사실을 좋아합니다. 무심코,이 버전은 단계를 하드 코딩했습니다. 예 : 체인에 새로운 중간 단계를 추가하려면 기존 클래스를 수정해야합니다. 더 중요하게는 각 단계는 다음 단계에 대한 지식을 가지고 있습니다 (이 경우에는 포함/생성). 나는 여기에 커플 링을 느슨하게했다. – Gishu

+0

예, 동의합니다. 그것의 더 많은 디자인 변경. 이런 식으로 표현하는 것이 논리적 인 것처럼 보일 수 있지만 필요가 다를 수 있습니다. 방금 내 생각을 발표했다. 진정으로 그것은 디자인의 필요성에 달려 있습니다. 귀하의 예는 대리인의 사용을 설명하기에 충분할 정도로 잘 수행됩니다. 현재 대부분의 코드를 생략했기 때문에 코드가 더 길어 보일 수도 있습니다. D – Nayan

+0

-1 : 다음 단계의 책임으로 불만 사항을 제기하는 코드가 누락 된 것 같습니다. 네가 동의하지 않으면 나에게 알려줘. –