🎉 Ура! Після трьох років роботи, я нарешті випустив англійську версію книжки про патерни! Ось вона »

C#: Спостерігач

Observer Спостерігач Observer

Спостерігач — це поведінковий патерн, який дозволяє об’єктам повідомляти інші об’єкти про зміни свого стану.

При цьому спостерігачі можуть вільно підписуватися і відписуватись від цих повідомлень.

Детальніше про Спостерігача

Особливості паттерна на C#

Складність:

Популярність:

Застосування: Спостерігач часто зустрічається в коді C#, особливо там, де до відносин між компонентами застосовується модель подій. Спостерігач дозволяє окремим компонентам реагувати на події, які відбуваються в інших компонентах.

Ознаки застосування патерну: Спостерігач визначається за механізмом підписки та методами повідомлення, які викликають компоненти програми.

Приклад: Структура патерну

Цей приклад показує структуру патерну Спостерігач, а саме — з яких класів він складається, які ролі ці класи виконують і як вони взаємодіють один з одним.

Program.cs: Приклад структури патерну

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RefactoringGuru.DesignPatterns.Observer.Structural
{
    public interface SplObserver
    {
        void update(SplSubject subject);
    }

    public interface SplSubject
    {
        void attach(SplObserver observer);

        void detach(SplObserver observer);

        void notify();
    }

    public class Subject : SplSubject
    {
        public int State { get; set; } = -0;

        private List<SplObserver> _observers = new List<SplObserver>();

        public void attach(SplObserver observer)
        {
            Console.Write("Subject: Attached an observer.\n");
            this._observers.Add(observer);
        }

        public void detach(SplObserver observer)
        {
            foreach(var elem in _observers)
            {
                if(elem == observer)
                {
                    _observers.Remove(observer);
                    Console.Write("Subject: Detached an observer.\n");
                    break;
                }
            }
        }

        public void notify()
        {
            Console.Write("Subject: Notifying observers...\n");

            foreach(var observer in _observers)
            {
                observer.update(this);
            }
        }

        public void someBusinessLogic()
        {
            Console.Write("\nSubject: I'm doing something important.\n");
            this.State = new Random().Next(0, 10);

            Thread.Sleep(15);

            Console.Write("Subject: My state has just changed to: " + this.State + "\n");
            this.notify();
        }
    }

    class ConcreteObserverA : SplObserver
    {
        public void update(SplSubject subject)
        {
            if(!(subject is Subject))
            {
                return;
            }
            
            if((subject as Subject).State < 3)
            {
                Console.Write("ConcreteObserverA: Reacted to the event.\n");
            }
        }
    }

    class ConcreteObserverB : SplObserver
    {
        public void update(SplSubject subject)
        {
            if (!(subject is Subject))
            {
                return;
            }

            if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
            {
                Console.Write("ConcreteObserverB: Reacted to the event.\n");
            }
        }
    }

    class Client
    {
        public static void ClientCode()
        {
            var subj = new Subject();
            var o1 = new ConcreteObserverA();
            subj.attach(o1);

            var o2 = new ConcreteObserverB();
            subj.attach(o2);

            subj.someBusinessLogic();
            subj.someBusinessLogic();

            subj.detach(o2);

            subj.someBusinessLogic();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Client.ClientCode();
        }
    }
}

Output.txt: Результат виконання

Subject: Attached an observer.
Subject: Attached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 6
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event.

Subject: I'm doing something important.
Subject: My state has just changed to: 4
Subject: Notifying observers...
ConcreteObserverB: Reacted to the event.
Subject: Detached an observer.

Subject: I'm doing something important.
Subject: My state has just changed to: 8
Subject: Notifying observers...