Українська
Стандартні інтерфейси та вибір
Стандартні інтерфейси .NET
Бібліотека .NET широко використовує інтерфейси. Найпоширеніші:
IComparable<T>– природний порядок об’єктів: методCompareTo(T other)повертає від’ємне число, 0 або додатне число. Його використовуєArray.Sort(array)(https://learn.microsoft.com/dotnet/api/system.icomparable-1);IComparer<T>– окремий об’єкт-порівнювач з методомCompare(T x, T y); дозволяє сортувати одні й ті самі об’єкти різними способами:Array.Sort(array, new ByAge());IEquatable<T>– типізований методEquals(T other)без упакування й приведення; реалізують разом із перевизначеннямEquals(object)іGetHashCode;ICloneable– методClone(); використовується рідко, бо не визначає, глибока чи поверхнева копія створюється;IDisposable– методDispose()для звільнення ресурсів (файлів, з’єднань); працює з операторомusing;IEnumerable<T>– можливість перебору вforeach; детально – тема 13.
IDisposable і using
Збирач сміття звільняє пам’ять, але не знає, коли закривати файли, мережеві з’єднання чи інші ресурси операційної системи. Клас, що володіє такими ресурсами, реалізує IDisposable, а код, який його використовує, викликає Dispose у блоці finally. Оператор using робить це автоматично (https://learn.microsoft.com/dotnet/standard/garbage-collection/implementing-dispose):
cs
using (var session = new DeviceSession("Сканер"))
{
session.Send("SCAN");
} // тут викликається Dispose
using var printer = new DeviceSession("Принтер");
printer.Send("PRINT"); // Dispose – у кінці блокуДруга форма (using-оголошення) викликає Dispose у кінці блоку, в якому оголошено змінну. Dispose викликається навіть у разі винятку. Метод Dispose має бути безпечним для повторного виклику, а методи вже звільненого об’єкта генерують ObjectDisposedException.
Абстрактний клас чи інтерфейс
Порівняння наведено в табл. 10.1.
Таблиця 10.1. Порівняння абстрактних класів та інтерфейсів
| Ознака | Абстрактний клас | Інтерфейс |
|---|---|---|
| стан (поля) | може мати поля екземпляра | полів екземпляра не має |
| конструктори | має, викликаються через base(…) | не має |
| множинність | лише один базовий клас | клас реалізує кілька інтерфейсів |
| реалізація | звичайні, віртуальні й абстрактні члени | лише члени за замовчуванням і статичні |
| модифікатори доступу | будь-які, зокрема protected | члени зазвичай публічні |
| відношення | «є» – спільна основа споріднених класів | «уміє» – здатність, контракт |
| типове використання | спільний код і стан ієрархії, шаблонний метод | слабке зв’язування, кілька ролей об’єкта, підміна реалізацій |
Практичне правило: інтерфейс описує, що об’єкт уміє (IComparable, IDisposable, ISwitchable), абстрактний клас – чим споріднені класи є і який код у них спільний. Нерідко поєднують обидва: інтерфейс визначає контракт, а абстрактний клас надає часткову реалізацію.
Програмування на рівні інтерфейсів
Якщо метод або клас залежить від інтерфейсу, а не від конкретного класу, реалізацію можна замінити, не змінюючи код, що її використовує. Наприклад, метод звіту, який приймає IReportFormatter, однаково працює з текстовим, CSV чи Markdown-форматувальником, а в тестах (тема 18) його можна перевірити з простою тестовою реалізацією. Таке слабке зв’язування (loose coupling) лежить в основі принципів SOLID (тема 17).