ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디자인패턴, Observer 옵저버
    공부정리/디자인패턴 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#
    반응형

    댓글

Designed by Tistory.