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();
}
}
}
class Car {
public void Stop() => Console.WriteLine("🛑 🚗 Авто зупинилось.");
public void Go() => Console.WriteLine("✅ 🚗 Авто поїхало!");
public void GetReady() => Console.WriteLine("⚠ 🚗 Авто готується до руху.");
public void Idle() => Console.WriteLine("🔄 🚗 Очікує, поки з'явиться сигнал.");
}
class Pedestrian {
public void Walk() => Console.WriteLine("🚶♂️ ✅ Пішохід переходить.");
public void Wait() => Console.WriteLine("⏳ 🚶♂️ Пішохід чекає дозволу.");
public void GetReady() => Console.WriteLine("⚠ 🚶♂️ Пішохід готується йти.");
public void Confused() => Console.WriteLine("😨 🚶♂️ Пішохід розгублений.");
}
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):
⚠ Світлофор НЕ ПРАЦЮЄ!
🔄 🚗 Очікує, поки з'явиться сигнал.
😨 🚶♂️ Пішохід �озгублений.
TrafficLight лише один по всій програмі.Цей приклад демонструє об'єктно-орієнтовані підходи: інкапсуляцію, події, делегати, взаємодію об'єктів та шаблон Singleton.
Класи: Car (машина), Parking (стоянка)- генеруються дві події, Sequrity (охоронець)-обробник події , Police (поліція) обробники двох подій та Program (тестуючий)
У класі Parking виникає дві статичні події:
Відпрацювання 1: виникла лише подія NotPlaces.

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

Поле: номер машини
Властивість для читання поля номер машини
Конструктор із параметром.
public class Car
{
string nomer;
public string Nomer
{
get { return nomer; }
}
public Car(string nomer)
{
this.nomer = nomer;
}
}
Поле: ім'я
Властивості для читання поля ім'я.
Конструктор з параметром.
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;
}
Поле: ім'я
Властивість для читання поля ім'я.
Конструктор із параметрами.
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} приїхав на стоянку");
}
Події виникають у цьому класі. Тому тут описуються і події та відповідні їм делегати. Події статичні, оскільки відбуваються у цьому класі, а відмовляємось від них в інших класах.
Делегатів два, тому що у їхніх обробників різна сигнатура: один тип без параметрів і без значення, що повертається, другий з цілим параметром і без значення, що повертається.
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); // Викликаємо подію сигналізації
}
}
}
Створимо об'єкти трьох класів: 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 викликаються:
При події 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(); // Очікування натискання клавіші