Об’єкт спостереження: Door (двері в будинку). Спостерігачі: Dog (собака), Cat (кіт), Parrot (папуга). Двері мають три стани: «відчинені», «зачинені і тиша», «зачинені і хтось стукає».
| Стан Door | Dog | Cat | Parrot |
|---|---|---|---|
| зачинені і тиша | «Я собака, яка чекає гостей.» | «Я кіт, який нікого не чекає.» | «Сиджу за ґратами в клітці дурній...» |
| зачинені і хтось стукає | «Гав, гав, гав. Не бійтеся, я не кусаю гостей.» | «Мяу, мяу, мяу. Сподіваюся, ви не до мене прийшли?» | «Свободу папугам!» |
| відчинені | «Гав, гав, гав. Заходьте, двері відкриті.» (відписується) | «Мяу, мяу, мяу. Якщо вже приперлися — то принесли рибку?» (відписується) | «Вилітаю на Гаїті!» (відписується) |
// <summary>
// Демонстрація шаблонів Singleton (Door) і Observer (Dog, Cat, Parrot).
// Двері можуть бути в станах: "відчинені", "зачинені і тиша", "зачинені і хтось стукає".
// Зміна стану викликає сповіщення всіх підписаних спостерігачів.
// </summary>
using System;
using System.Collections.Generic;
namespace DoorObserverDemo
{
/// <summary>
/// Інтерфейс спостерігача. Будь-який спостерігач має вміти реагувати на зміну стану дверей.
/// </summary>
public interface IObserver
{
void Update(string doorState, Door door);
}
/// <summary>
/// Door — об'єкт спостереження (Subject) і Singleton (єдиний екземпляр).
/// </summary>
public class Door
{
// Єдиний екземпляр створюється ліниво або завчасно. Тут — завчасно (eager singleton).
private static readonly Door instance = new Door();
// Колекція підписаних спостерігачів
private readonly List<IObserver> observers = new List<IObserver>();
// Поточний стан дверей
private string state = "зачинені і тиша";
// Приватний конструктор забороняє new Door() ззовні
private Door() { }
/// <summary>Публічний доступ до єдиного екземпляра Door.</summary>
public static Door Instance => instance;
/// <summary>Підписати спостерігача.</summary>
public void Attach(IObserver observer)
{
if (observer != null && !observers.Contains(observer))
observers.Add(observer);
}
/// <summary>Відписати спостерігача.</summary>
public void Detach(IObserver observer)
{
if (observer != null)
observers.Remove(observer);
}
/// <summary>
/// Змінити стан дверей і сповістити всіх спостерігачів.
/// </summary>
public void ChangeDoor(string newState)
{
state = newState;
Console.WriteLine($"\n=== Двері тепер у стані: {state} ===");
Notify();
}
/// <summary>Сповістити всіх підписаних спостерігачів.</summary>
private void Notify()
{
// Копія списку, щоб дозволити відписку під час ітерації (без винятків)
foreach (var observer in new List<IObserver>(observers))
{
observer.Update(state, this);
}
}
}
/// <summary>Конкретний спостерігач — Собака.</summary>
public class Dog : IObserver
{
public void Update(string doorState, Door door)
{
if (doorState == "зачинені і хтось стукає")
{
TukTuk();
}
else if (doorState == "зачинені і тиша")
{
Vois();
}
else if (doorState == "відчинені")
{
DoorOpen();
door.Detach(this); // Відписується
}
}
private void TukTuk()
{
Console.WriteLine("Собака: Гав, гав, гав. Не бійтеся, я не кусаю гостей.");
}
private void Vois()
{
Console.WriteLine("Собака: Я собака, яка чекає гостей.");
}
private void DoorOpen()
{
Console.WriteLine("Собака: Гав, гав, гав. Заходьте, двері відкриті.");
}
}
/// <summary>Конкретний спостерігач — Кіт.</summary>
public class Cat : IObserver
{
public void Update(string doorState, Door door)
{
if (doorState == "зачинені і хтось стукає")
{
TukTuk();
}
else if (doorState == "зачинені і тиша")
{
Vois();
}
else if (doorState == "відчинені")
{
DoorOpen();
door.Detach(this); // Відписується
}
}
private void TukTuk()
{
Console.WriteLine("Кіт: Мяу, мяу, мяу. Сподіваюся, ви не до мене прийшли?");
}
private void Vois()
{
Console.WriteLine("Кіт: Мяу, мяу, мяу. Я кіт, який нікого не чекає.");
}
private void DoorOpen()
{
Console.WriteLine("Кіт: Мяу, мяу, мяу. Якщо вже приперлися — то принесли рибку?");
}
}
/// <summary>Конкретний спостерігач — Папуга.</summary>
public class Parrot : IObserver
{
public void Update(string doorState, Door door)
{
if (doorState == "зачинені і хтось стукає")
{
TukTuk();
}
else if (doorState == "зачинені і тиша")
{
Vois();
}
else if (doorState == "відчинені")
{
DoorOpen();
door.Detach(this); // Відписується
}
}
private void TukTuk()
{
Console.WriteLine("Папуга: Свободу папугам!");
}
private void Vois()
{
Console.WriteLine("Папуга: Сиджу за ґратами в клітці дурній...");
}
private void DoorOpen()
{
Console.WriteLine("Папуга: Вилітаю на Гаїті!");
}
}
/// <summary>Тестувальник — Program.</summary>
class Program
{
static void Main(string[] args)
{
Door door = Door.Instance;
Dog dog = new Dog();
Cat cat = new Cat();
Parrot parrot = new Parrot();
// Підписуємо всіх тварин
door.Attach(dog);
door.Attach(cat);
door.Attach(parrot);
// Зміна станів дверей
door.ChangeDoor("зачинені і тиша");
door.ChangeDoor("зачинені і хтось стукає");
door.ChangeDoor("відчинені");
Console.WriteLine("\nДемонстрація завершена.");
}
}
}
dotnet new console -n DoorObserverDemo
cd DoorObserverDemo
# замініть Program.cs вмістом зі вставки вище
dotnet run