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