Назад Вперед Зміст

Розширений приклад: Світлофор (події + делегати + Singleton)

Класс Світлофор (реалізовано як Singleton)

class TrafficLight {
    private static readonly TrafficLight instance = new TrafficLight();
    private TrafficLight() { }
    public static TrafficLight Instance => instance;

    public delegate void LightChangeHandler();

    public event LightChangeHandler GreenLight;
    public event LightChangeHandler RedLight;
    public event LightChangeHandler YellowLight;
    public event LightChangeHandler BlackOut;

    public void ChangeLight(int i) {
        if (i % 2 == 0 && RedLight != null) {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("🚦 Горить ЧЕРВОНИЙ сигнал");
            Console.ResetColor();
            RedLight();
        }
        else if (i % 3 == 0 && GreenLight != null) {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("🚦 Горить ЗЕЛЕНИЙ сигнал");
            Console.ResetColor();
            GreenLight();
        }
        else if (i % 5 == 0 && YellowLight != null) {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("🚦 Горить ЖОВТИЙ сигнал");
            Console.ResetColor();
            YellowLight();
        }
        else if (BlackOut != null) {
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine("⚠ Світлофор НЕ ПРАЦЮЄ!");
            Console.ResetColor();
            BlackOut();
        }
    }
}

Класс Car


class Car {
    public void Stop() => Console.WriteLine("🛑 🚗 Авто зупинилось.");
    public void Go() => Console.WriteLine("✅ 🚗 Авто поїхало!");
    public void GetReady() => Console.WriteLine("⚠ 🚗 Авто готується до руху.");
    public void Idle() => Console.WriteLine("🔄 🚗 Очікує, поки з'явиться сигнал.");
}

Класс Pedestrian


class Pedestrian {
    public void Walk() => Console.WriteLine("🚶‍♂️ ✅ Пішохід переходить.");
    public void Wait() => Console.WriteLine("⏳ 🚶‍♂️ Пішохід чекає дозволу.");
    public void GetReady() => Console.WriteLine("⚠ 🚶‍♂️ Пішохід готується йти.");
    public void Confused() => Console.WriteLine("😨 🚶‍♂️ Пішохід розгублений.");
}

Класс Program


class Program {
    static void Main() {
        TrafficLight light = TrafficLight.Instance;
        Car car = new Car();
        Pedestrian pedestrian = new Pedestrian();

        light.GreenLight += car.Go;
        light.GreenLight += pedestrian.Wait;
        light.RedLight += car.Stop;
        light.RedLight += pedestrian.Walk;
        light.YellowLight += car.GetReady;
        light.YellowLight += pedestrian.GetReady;
        light.BlackOut += car.Idle;
        light.BlackOut += pedestrian.Confused;

        for (int i = 1; i <= 10; i++) {
            Console.WriteLine($"\n🔄 Зміна сигналу (Крок {i}):");
            light.ChangeLight(i);
        }
    }
}

Сімулятор світлофора


 🚗 Очікує, поки з'явиться си�нал.
😨 🚶‍♂️ Пішохід розгублений.

� Зміна сигналу (Крок 2):
🚦 Горить ЧЕРВОНИЙ сигнал
🛑 🚗 Авто зупинилось.
🚶‍♂️ ✅ Пішохід переходить.

🔄 Зміна сигналу (Крок 3):
🚦 Горить ЗЕЛЕНИЙ сигнал
✅ 🚗 Авто поїхало!
⏳ 🚶‍♂️ Пішохід че�ає дозволу.

🔄 Зміна сигналу (Крок 4):
🚦 Горить ЧЕРВОНИЙ сигнал
🛑 🚗 Авто зупинилось.
🚶‍♂️ ✅ Пішохід переходить.

🔄 Зміна сигналу (Крок 5):
🚦 Горить ЖОВТИЙ сигнал
⚠ 🚗 Авто готується до ру�у.
⚠ 🚶‍♂️ Пішохід готується йти.

🔄 Зміна сигна�у (Крок 6):
🚦 Горить ЧЕРВОНИЙ сигнал
🛑 🚗 Ав�о зупинилось.
🚶‍♂️ ✅ Пішохід переходить.

🔄 Зміна сигналу (Крок 7):
⚠ Світлофор НЕ ПРАЦЮЄ!
🔄 🚗 Очікує, поки з'явиться сигнал.
😨 🚶‍♂️ Пішохід �озгублений.

Пояснення логіки

Цей приклад демонструє об'єктно-орієнтовані підходи: інкапсуляцію, події, делегати, взаємодію об'єктів та шаблон Singleton.

Приклад 2

Проект «Автостоянка»

Класи: Car (машина), Parking (стоянка)- генеруються дві події, Sequrity (охоронець)-обробник події , Police (поліція) обробники двох подій та Program (тестуючий)

У класі Parking виникає дві статичні події:

  1. Подія NotPlaces. Виникає, коли на стоянці немає місць. Делегат NotPlacesEventHandler. На подію підписуються класи Sequrity та Police. Охоронець закриває стоянку. Поліцейський включає відеоспостереження.
  2. Подія SignalTriggered. Спрацювала сигналізація на стоянці. Подія виникає випадково. Делегат SignalTriggeredEventHandler (int k). Параметр k лічильник спрацьовувань. На подію підписується клас Police. Поліцейський приїжджає на стоянку після кожного спрацювання.

Відпрацювання 1: виникла лише подія NotPlaces.

Відпрацювання 2: виникла подія NotPlaces і 3 рази виникла подія SignalTriggered.

Клас Car

Поле: номер машини

Властивість для читання поля номер машини

Конструктор із параметром.

public class Car
{
    string nomer;
    public string Nomer
    {
        get { return nomer; }
    }
    public Car(string nomer)
    {
        this.nomer = nomer;
    }
}

Клас Sequrity (охоронець)

Поле: ім'я

Властивості для читання поля ім'я.

Конструктор з параметром.

public class Security
{
    string name;
    public string Name
    {
        get { return name; }
    }
    public Security(string name)
    {
        this.name = name;
    }
}

Обробник події NotPlaces:

// обробник події NotPlaces
public void CloseParking()
{
    Console.ForegroundColor = System.ConsoleColor.Blue;
    Console.WriteLine("Wecr нет. Охоронець {0} закрив стоянку", name);
    // відписуємось від статичної події
    Parking.NotPlaces -= this.CloseParking;
}

Клас Police (поліція)

Поле: ім'я

Властивість для читання поля ім'я.

Конструктор із параметрами.

public class Police
{
    string name;
    public string Name
    {
        get { return name; }
    }

    public Police(string name)
    {
        this.name = name;
    }
}

Обробник події NotPlaces:

public void VideoSwitchOn()
{
    Console.ForegroundColor = System.ConsoleColor.Magenta;
    Console.WriteLine("Ночной {0} включил видеонаблюдение", name);
    // отписываемся от события
    Parking.NotPlaces -= this.VideoSwitchOn;
}

Обробник події SignalTriggered:

public void DroveOutAddress(int alarmCount)
    {
        Console.ForegroundColor = ConsoleColor.Magenta;
        Console.WriteLine($"Спрацювала сигналізація {alarmCount} раз");
        Console.WriteLine($"Поліцейский {name} приїхав на стоянку");
    }

Клас Parking (стоянка)

Події виникають у цьому класі. Тому тут описуються і події та відповідні їм делегати. Події статичні, оскільки відбуваються у цьому класі, а відмовляємось від них в інших класах.

Делегатів два, тому що у їхніх обробників різна сигнатура: один тип без параметрів і без значення, що повертається, другий з цілим параметром і без значення, що повертається.

public class Parking
{
    // Делегат для події SignalTriggered
    public delegate void SignalTriggeredEventHandler(int k);
    // Подія SignalTriggered
    public static event SignalTriggeredEventHandler SignalTriggered;
    
    // Делегат для події NotPlaces
    public delegate void NotPlacesEventHandler();
    // Подія NotPlaces
    public static event NotPlacesEventHandler NotPlaces;

SignalTriggeredEventHandler - делегат для події, яка приймає параметр int k (кількість спрацювань сигналізації).

NotPlacesEventHandler - делегат для події без параметрів (сигналізує про відсутність місць).

Статичні події:

SignalTriggered - викликається при спрацюванні сигналізації.

NotPlaces - викликається, коли немає вільних місць.

Поля: адреса стоянки, кількість місць, List <Car> - список машин, логічна змінна: чи є місця на стоянці, лічильник спрацьовувань сигналізації.

Властивість для читання поля – чи є місця.

Конструктор із параметрами.

// Поля класу
bool therePlaces; // чи є вільні місця
string adr;      // адреса парковки
int AllPlaces;   // загальна кількість місць
List cars;  // колекція машин на парковці
int t;           // лічильник спрацювань сигналізації

// Властивість
public bool TherePlaces
{
    get { return therePlaces; }
}

// Конструктор
public Parking(string adr, int AllPlaces)
{
    this.adr = adr;
    this.AllPlaces = AllPlaces;
    cars = new List(0);
    this.therePlaces = true;
    t = 0;
}

Метод, в якому виникає подія NotPlaces та подія SignalTriggered

public void PushCar(Car car)
{
    Random rand = new Random();
    
    // Перевірка на відсутність вільних місць
    if ((NotPlaces != null) && cars.Count > AllPlaces - 1)
    {
        NotPlaces(); // Викликаємо подію "немає місць"
        therePlaces = false; // Оновлюємо статус парковки
    }
    else
    {
        // Додаємо машину на парковку
        cars.Add(car);
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine($"На стоянку прибула {car.Nomer}");
        
        // Випадкова перевірка спрацювання сигналізації (1 шанс з 8)
        int chance = rand.Next(1, 8);
        if (chance == 1)
        {
            t++; // Збільшуємо лічильник спрацювань
            SignalTriggered?.Invoke(t); // Викликаємо подію сигналізації
        }
    }
}

Клас Program (тестуючий)

Створимо об'єкти трьох класів: parking, sequrityMan, policeMan

class Program
{
    static void Main(string[] args)
    {
        // Створення об'єктів системи парковки
        Parking parking = new Parking("вул. Краснова", 10);
        Security securityMan = new Security("Микола");
        Police policeMan = new Police("Олександр");

        // Підписка на події парковки
        Parking.NotPlaces += securityMan.CloseParking;
        Parking.SignalTriggered += policeMan.DroveOutAddress;
        
        // Інший код ініціалізації...
    }
}

Підпишемося на події.

На подію NotPlaces підпишемо об'єкти sequrityMan та policeMan

На подію SignalTriggered підпишемо об'єкт policeMan

Оскільки події статичні, то застосовуємо їх не об'єкту, а до класу.

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

// Краще використовувати окремі методи для підписки
void SubscribeToEvents()
{
    Parking.NotPlaces += securityMan.CloseParking;
    Parking.NotPlaces += securityMan.VideoSwitchOn;
    Parking.SignalTriggered += policeMan.DroveOutAddress;
}

При виникненні події NotPlaces викликаються:

  1. CloseParking() - закриття парковки
  2. VideoSwitchOn() - включення камер

При події SignalTriggered викликається DroveOutAddress(t).

У циклі, поки у об'єкта parking значення логічного поля = true (місця є), виконуємо:

int carNumber = 1;  // Лічильник для нумерації машин

while (parking.TherePlaces)  // Цикл виконується, доки є вільні місця
{
    // Створюємо новий автомобіль з унікальним номером
    Car newCar = new Car($"A{carNumber:000}");  // Формат: A001, A002 тощо
    
    // Спроба додати машину на парковку
    parking.PushCar(newCar);
    
    carNumber++;  // Збільшуємо лічильник
    
    // Невелика затримка для імітації реального процесу
    Thread.Sleep(100); 
}

Console.WriteLine("\nПарковка заповнена!");
Console.ReadKey();  // Очікування натискання клавіші

Назад Вперед Зміст