15. 책임 연쇄 패턴(Chain of Responsibility Pattern) 구현

15.4 구현

 책임 연쇄 패턴에 대한 예제 프로그램을 구현하는 순서는 ChangeHandler, ChangeHandler 에서 파생된 형식들, UIPart와 데모 코드 순으로 하겠습니다.

15.4.1 ChangeHandler

 ChangeHandler에서는 사진을 보정하라는 명령을 받아서 수행하는 메서드를 약속해야 할 것입니다.

public abstract string ChangeRequest(List<int> mode,string picture);

 그리고 자신 뒤에 연결할 ChangeHandler 개체를 설정하고 얻어오는 속성을 제공해야 할 것입니다.

public ChangeHandler Successor
{
    get;
    set;
}

  그리고 명령이 자신에게 온 것인지 확인할 수 있게 하기 위해 생성자 메서드에서는 핸들러 id를 부여받게 하였고 보정 명령으로 전달된 수행할 핸들러 id 집합인 Mode 컬렉션에 자신이 속하는지를 확인하는 메서드를 파생 클래스에서 사용할 수 있게 제공하고 있습니다.

protected bool IncludeMode(List<int> mode);

▶ ChangeHandler.cs

using System.Collections.Generic;

namespace ChainofResponsibility
{
    abstract class ChangeHandler
    {
        public ChangeHandler Successor
        {
            get;
            set;
        }
        readonly int hid;
        public ChangeHandler(int hid)
        {
            this.hid = hid;
            Successor = null;
        }
        public abstract string ChangeRequest(List<int> mode,string picture);
        protected bool IncludeMode(List<int> mode)
        {
            foreach (int m in mode)
            {
                if (m == hid)
                {
                    return true;
                }
            }
            return false;
        }
    }
}


15.4.2 ChangeHandler 에서 파생된 형식들

 ChangeHander에서 파생된 형식들에는 칼라를 흑백으로 보정하는 GrayChangeHandler와 적목 보정을 수행하는 RedEyeChangeHandler, 날카로운 부분을 부드럽게 보정하는 SoftChangeHandler를 구현하기로 하였습니다.

 각 클래스에서는 ChangeHander에 약속된 ChangeRequest 메서드를 구현해야 할 것입니다. 메서드 내에서는 먼저 자신이 처리할 메시지인지를 확인을 하여 맞다면 처리를 해야 합니다. 그리고, 자신에게 연결된 다른 ChangeHandler 개체가 있다면 메시지를 전달하도록 하겠습니다. 어떤 경우에는 자신에게 전달된 메시지를 자신이 처리를 하게 되었을 때 다른 개체에게 전달할 필요가 없는 경우도 있습니다.

▶ GrayChangeHandler.cs  

using System.Collections.Generic;
namespace ChainofResponsibility
{
    class GrayChangeHandler:ChangeHandler
    {
        public GrayChangeHandler(int hid):base(hid)
        {
        }
        public override string ChangeRequest(List<int> mode, string picture)
        {
            if(IncludeMode(mode))
            {
                picture = picture.Replace("칼라","흑백");
            }
            if (Successor != null)
            {
                picture = Successor.ChangeRequest(mode, picture);
            }
            return picture;
        }
    }
}

▶ RedEyeChangeHandler.cs  

using System.Collections.Generic;
namespace ChainofResponsibility
{
    class RedEyeChangeHandler:ChangeHandler
    {
        public RedEyeChangeHandler(int hid):base(hid)
        {
        }
        public override string ChangeRequest(List<int> mode, string picture)
        {
            if (IncludeMode(mode))
            {
                picture = picture.Replace("빨간눈", "정상눈");
            }
            if (Successor != null)
            {
                picture = Successor.ChangeRequest(mode, picture);
            }
            return picture;
        }
    }
}

▶ SoftChangeHandler.cs  

using System.Collections.Generic;
namespace ChainofResponsibility
{
    class SoftChangeHanler:ChangeHandler
    {
        public SoftChangeHanler(int hid)
            : base(hid)
        {
        }
        public override string ChangeRequest(List<int> mode, string picture)
        {
            if (IncludeMode(mode))
            {
                picture = picture.Replace("날카로운", "부드러운");
            }
            if (Successor != null)
            {
                picture = Successor.ChangeRequest(mode, picture);
            }
            return picture;
        }
    }
}


15.4.3 UIPart와 데모 코드

 이번에는 메시지를 ChangeHander 개체에게 전달하는 주체인 UIPart를 구현해 보기로 합시다.

 UIPart에는 보정 명령을 수신할 개체를 체인 형태로 관리할 것인데 이를 위해 체인의 맨 앞과 맨 뒤에 있는 핸들을 갖는 멤버 필드를 유지하겠습니다. 그리고, 체인에 핸들을 추가하는 메서드와 사진을 보정하는 메서드를 제공하겠습니다.

 ▶ UIPart.cs  

using System.Collections.Generic;
namespace ChainofResponsibility
{
    class UIPart
    {
        ChangeHandler head = null;
        ChangeHandler tail = null;
        public void AddChangeHandler(ChangeHandler handler)
        {
            if(head != null)
            {		
                tail.Successor= handler;
                tail = handler;
            }
            else
            {
                head = tail = handler;
            }
        }
        public string ChangeRequest(List<int> mode,string subject)
        {
            if(head!=null)
            {
                return head.ChangeRequest(mode,subject);
            }
            return subject;
        }
    }
}

 데모 코드에서는 여러 가지 형태로 명령을 수행할 개체의 핸들러 id들을 설정하여 사진 보정 명령을 내리고 그 결과 사진을 화면에 출력하는 것으로 테스트를 수행하겠습니다.

  ▶ UIPart.cs  

using System;
using System.Collections.Generic;
namespace ChainofResponsibility
{
    class Program
    {
        static void Main(string[] args)
        {
            string picture = string.Empty;
            List<int> mode = new List<int>();
            ChangeHandler[] handlers = new ChangeHandler[3];
            handlers[0] = new GrayChangeHandler(0);
            handlers[1] = new SoftChangeHanler(1);
            handlers[2] = new RedEyeChangeHandler(2); 
            UIPart uipart = new UIPart();
            uipart.AddChangeHandler(handlers[0]);
            uipart.AddChangeHandler(handlers[1]);
            uipart.AddChangeHandler(handlers[2]);
            picture = uipart.ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
            Console.WriteLine(picture);
            mode.Add(0);
            picture = uipart.ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
            Console.WriteLine(picture);
            mode.Add(2);
            picture = uipart.ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
            Console.WriteLine(picture);
            mode.Add(1);
            picture = uipart.ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
            Console.WriteLine(picture);
        }
    }
}
[그림] 책임 연쇄 패턴 실행 화면
[그림] 책임 연쇄 패턴 실행 화면