기타 정보/디자인패턴

디자인패턴, Observer 옵저버

FreeBear 2022. 2. 11. 01:02
반응형

Observer의 뜻

영어 사전으로 보면 다음의 뜻을 가진다.

영어사전

observer
미국식[əb│zɜːrvə(r)]
영국식[əb│zɜːvə(r)]
명사
  • 1

    보는 사람, 목격자

    According to observers, the plane exploded shortly after take-off.
    목격자들에 의하면 그 비행기는 이륙 직후에 폭발했다.

  • 2

    (회의·수업 등의) 참관인[옵서버]

    A team of British officials were sent as observers to the conference.
    영국 공무원들 한 팀이 그 총회에 참관인으로 파견되었다.

  • 3

    관찰자, 관측자

    a royal observer
    왕실 입회인

[네이버 영어사전에서 발췌]

 

Observer 패턴

Observer 패턴은 관찰자, 참관인을 뜻하는 패턴으로 객체의 상태 변화를 관찰하는 관찰자를 두어 객체 사이에 일 대 다의 의존 관계를 정의해 두고, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 만든다. 의존성을 가지는게 주요 특징이어서 Dependent(종속자)라고도 하고, 메인에 서브가 달라붙는 형식이기 때문에 Publish-Subscribe(발행-구독)라고도 한다.

즉, 관찰자 A에 객체B, C, D가 등록되고, B에서 id정보가 바뀌면 A를 통해 C, D에서도 id정보가 자동으로 업데이트되도록 구현하는 것이 옵저버 패턴이다.

 

구현

c#을 이용해 핵심만 구현해 보았다.

using TEST_Observer.Models;

namespace TEST_Observer
{
    public interface IObserver
    {
        void UpdateInfo(UserInfo userInfo);
    }

    public interface ISubject
    {
        void Attach(IObserver o);
        void Detach(IObserver o);
        void Notify(UserInfo userInfo);
    }
}

[Observer 인터페이스]

 

using System.Collections.Generic;
using TEST_Observer.Models;

namespace TEST_Observer
{
    public class Subject : ISubject
    {
        List<IObserver> observers = new List<IObserver>();

        public void Notify(UserInfo userInfo)
        {
            foreach (IObserver o in observers)
            {
                o.UpdateInfo(userInfo);
            }
        }

        public void Attach(IObserver o)
        {
            observers.Add(o);
        }

        public void Detach(IObserver o)
        {
            observers.Remove(o);
        }
    }
}

[관찰자 객체]

 

이 코드에서 핵심은 Observer가 수행할 인터페이스를 만든 후 관찰자 객체에서 해당 인터페이스를 사용하고, 옵저버에 등록 혹은 삭제, 알림 등 이벤트를 생성해주는 것이다.

 

C# Winform에서 구현 한 예제

IObserver, ISubject인터페이스는 위에 작성한 코드와 동일하다.

 

관찰자가 되는 메인이 되는 폼, Subject 클래스를 FormMain에서 다음과 같이 작성한다.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TEST_Observer.Models;

namespace TEST_Observer
{
    public partial class FormMain : Form, ISubject
    {
        List<IObserver> observers = new List<IObserver>();

        public FormMain()
        {
            InitializeComponent();
        }

        public void Notify(UserInfo userInfo)
        {
            foreach (IObserver o in observers)
            {
                o.UpdateInfo(userInfo);
            }
        }

        public void Attach(IObserver o)
        {
            observers.Add(o);
        }

        public void Detach(IObserver o)
        {
            observers.Remove(o);
        }

        private void buttonFormShow_Click(object sender, EventArgs e)
        {
            Form1 form1 = new Form1(this);
            form1.Show();
            Form2 form2 = new Form2(this);
            form2.Show();
            Form3 form3 = new Form3(this);
            form3.Show();
        }
    }
}

 

관찰 대상이 되는 폼, Form1, Form2, Form3의 코드는 다음과 같이 작성한다.

using System.Windows.Forms;
using TEST_Observer.Models;

namespace TEST_Observer
{
    public partial class Form1 : Form, IObserver
    {
        ISubject subject;

        public Form1(ISubject _subject)
        {
            subject = _subject;
            subject.Attach(this);
            InitializeComponent();
        }

        public void UpdateInfo(UserInfo userInfo)
        {
            labelUserName.Text = userInfo.UserName;
        }

        private void buttonUpdate_Click(object sender, System.EventArgs e)
        {
            UserInfo userInfo = new UserInfo();
            userInfo.UserName = textBoxUserName.Text;
            subject.Notify(userInfo);
        }
    }
}
using System.Windows.Forms;
using TEST_Observer.Models;

namespace TEST_Observer
{
    public partial class Form2 : Form, IObserver
    {
        ISubject subject;

        public Form2(ISubject _subject)
        {
            subject = _subject;
            subject.Attach(this);
            InitializeComponent();
        }

        public void UpdateInfo(UserInfo userInfo)
        {
            labelUserName.Text = userInfo.UserName;
        }

        private void buttonUpdate_Click(object sender, System.EventArgs e)
        {
            UserInfo userInfo = new UserInfo();
            userInfo.UserName = textBoxUserName.Text;
            subject.Notify(userInfo);
        }
    }
}
using System.Windows.Forms;
using TEST_Observer.Models;

namespace TEST_Observer
{
    public partial class Form3 : Form, IObserver
    {
        ISubject subject;

        public Form3(ISubject _subject)
        {
            subject = _subject;
            subject.Attach(this);
            InitializeComponent();
        }

        public void UpdateInfo(UserInfo userInfo)
        {
            labelUserName.Text = userInfo.UserName;
        }
    }
}

 

[이미지1] 정보 수정 버튼 클릭 전

 

[이미지2] Form1의 정보 수정 버튼 클릭 후

 

Form1에서 UserName 텍스트박스에 값을 입력하고, 정보 수정 버튼을 클릭하면 Form1뿐만 아니라 Form2, Form3의 labelUserName도 똑같이 변경된다.

 


프로젝트 파일 첨부

TEST_Observer.zip
0.06MB

 


참고 문헌

  • GoF의 디자인패턴

 

참고 사이트

    • 위키백과, 옵서버 패턴
    • dofactory, C# Observer
    • Refactoring.Guru, Observer in C#
반응형