21. 감시자 패턴(Observer Pattern) 구현

21.4 구현

감시자 패턴에 대한 예제 프로그램을 구현하는 순서는 Subject와 Picture, IUpdate와 각 뷰어, 데모 코드 순으로 하겠습니다.

21.4.1 Subject와 Picture

Subject는 상태 변경이 있을 때 감시자에게 변경을 통보하는 역할을 담당합니다. 이를 위해 감시자를 등록하는 메서드와 해제하는 메서드를 구현해야 합니다. 그리고, 상태 변경이 있을 때 등록된 모든 감시자들에게 변경된 사실을 통보를 하는 메서드도 구현합시다.

▶ Subject.cs

using System.Collections.Generic;
namespace Observer
{
    class Subject
    {
        List<IUpdate> observers = new List<IUpdate>();
        public void AddObserver(IUpdate observer)
        {
            observers.Add(observer);
        }
        public void RemoveObserver(IUpdate observer)
        {
            observers.Remove(observer);
        }
        public void Notify()
        {
            foreach (IUpdate observer in observers)
            {
                observer.Update();
            }
        }
    }
}

 그리고 Picture는 Subject를 기반으로 파생된 형식으로 정의합시다. 이를 통해 Picture에서는 자신이 상태가 변경되었을 때 누군한테 보내야 하는지에 대한 고민을 하지 않아도 됩니다. 단순히 기반 클래스의 상태 변경을 통보하는 Notify 메서드를 사용하면 됩니다. 이를 통해 Picutre는 자신의 상태가 변경되었을 때 영향을 받는 다른 형식들과의 의존 관계가 필요없게 되는 것입니다.

▶ Picture.cs 

using System;
namespace Observer
{
    class Picture:Subject
    {
        public string Name
        {
            get;
            private set;
        }
        public int Tone
        {
            get;
            private set;
        }
        public int Brightness
        {
            get;
            private set;
        }
        public int Saturation
        {
            get;
            private set;
        }
        public Picture(string name,int tone,int brightness,int saturation)
        {
            Name = name;
            Tone = tone;
            Brightness = brightness;
            Saturation = saturation;
        }
        public void Change(int tone,int brightness,int saturation)
        {
            Tone+=tone;
            Brightness += brightness;
            Saturation += saturation;
            Notify();
        }
        public void View()
        {
            Console.WriteLine("사진 파일명:{0}",Name);
            Console.WriteLine("    색조:{0} 명도:{1} 채도:",Tone,Brightness,Saturation);
        }
    }
}

21.4.2 IUpdate와 각 뷰어

IUpdate에서는 상태 변경을 통보 받았을 때 처리할 메서드에 대한 약속을 하면 됩니다. 그리고, 각 뷰어에서는 IUpdate에서 약속한 메서드를 구체적으로 구현해야 겠지요. ToneViewer에서는 Picture 개체의 색조값을 얻어와 이를 보여주고 다른 뷰어들도 자신이 보여줘야 할 정보를 얻어와서 보여줍니다.

▶ IUpdate.cs  

namespace Observer
{
    interface IUpdate
    {
        void Update();
    }
}

▶ ToneViewer.cs  

using System;
namespace Observer
{
    class ToneViewer:IUpdate
    {
        Picture picture = null;
        public ToneViewer(Picture picture)
        {
            this.picture = picture;
        }
        public void Update()
        {
            Console.WriteLine("이름:{0} 색조:{1}", picture.Name, picture.Tone);
        }
    }
}

▶ BrightnessViewer.cs  

using System;
namespace Observer
{
    class BrightnessViewer:IUpdate
    {
        Picture picture;
        public BrightnessViewer(Picture picture)
        {
            this.picture = picture;
        }
        public void Update()
        {
            Console.WriteLine("이름:{0} 명도:{1}", picture.Name, picture.Brightness);
        }        
    }
}

▶ SaturationViewer.cs 

using System;
namespace Observer
{
    class SaturationViewer :IUpdate
    {
        Picture picture = null;
        public SaturationViewer(Picture picture)
        {
            this.picture = picture;
        }
        public void Update()
        {
            Console.WriteLine("이름:{0} 채도:{1}", picture.Name, picture.Saturation);
        }
    }
}

21.4.3 데모 코드

데모 코드에서는 사진 개체와 각 뷰어 개체를 생성한 후에 사진 개체에 각 뷰어를 등록을 합니다. 그리고, 사진 개체의 정보를 변경하는 코드로 작성하겠습니다. 내부적으로 사진 개체의 기반 형식인 Subject의 Update 메서드에 의해 각 뷰어에게 변경된 사실이 통보될 것이며 각 뷰어에서는 필요한 정보를 요청하여 화면에 출력합니다.

 ▶ Program.cs

namespace Observer
{
    class Program
    {
        static void Main(string[] args)
        {
            Picture picture = new Picture("제주도의 밤",100,100,100);
            IUpdate[] observers = new IUpdate[3];
            observers[0] = new ToneViewer(picture);
            observers[1] = new BrightnessViewer(picture);
            observers[2] = new SaturationViewer(picture);
            picture.AddObserver(observers[0]);
            picture.AddObserver(observers[1]);
            picture.AddObserver(observers[2]);
            picture.Change(3,10,5);
        }
    }
}

▶ 실행 결과

이름:제주도의 밤, 색조:103
이름:제주도의 밤, 색조:110
이름:제주도의 밤, 색조:105