Коли команда / компанія постачає фреймворк / компілятор / набір інструментів, вони вже мають певний досвід, набір кращих практик. Вони поділяють це як настанови. Настанови - це рекомендації . Якщо вам не подобається, ви можете нехтувати ними. Компілятор все одно скомпілює ваш код. Хоча коли в Римі ...
Це моє бачення, чому команда TypeScript рекомендує не- I
префікс інтерфейсів.
Основним аргументом I
прихильників -prefix-for-interface є те, що префікс корисний для негайного прокручування (заглядання), чи є тип інтерфейсом. Заява про те, що префікс є корисним для негайного продирання (заглядання), є зверненням до угорської нотації . I
префікс для імені інтерфейсу, C
для класу, A
для абстрактного класу, s
для рядкової змінної, c
для змінної const, i
для цілочисельної змінної. Я погоджуюсь, що така обробка імен може надати вам інформацію про тип, не наводячи курсор миші на ідентифікатор або не переходячи до визначення типу за допомогою гарячої клавіші. Цю крихітну перевагу переважають недоліки угорських позначень та інші причини, згадані нижче. Угорські позначення не використовуються в сучасних рамках. C # маєI
префікс (і це єдиний префікс у C #) для інтерфейсів через історичні причини (COM). Ретроспективно один з архітекторів .NET (Бред Абрамс) вважає, що було б краще не використовувати I
префікс . TypeScript не містить COM-спадщини, отже, він не має I
правила -prefix-for-interface.
Причина №2- I
префікс порушує принцип інкапсуляції
Припустимо, ви отримаєте якусь чорну скриньку. Ви отримуєте посилання на тип, що дозволяє взаємодіяти з цим вікном. Вам не має бути все одно, це інтерфейс чи клас. Ви просто використовуєте його інтерфейсну частину. Вимагати знати, що це (інтерфейс, конкретна реалізація або абстрактний клас), є порушенням інкапсуляції.
Приклад: припустимо, вам потрібно виправити у своєму коді міф API Design: Interface as Contract, наприклад, видалити ICar
інтерфейс і використовувати Car
замість нього базовий клас. Тоді вам потрібно виконати таку заміну у всіх споживачів. I
-prefix веде до неявної залежності споживачів від деталей реалізації чорної скриньки.
Причина №3 Захист від неправильних імен
Розробники лінуються правильно думати про імена. Присвоєння імен є однією з двох важких речей в галузі інформатики . Коли розробнику потрібно витягти інтерфейс, просто додати літеру I
до назви класу, і ви отримаєте ім’я інтерфейсу. Заборона I
префіксу для інтерфейсів змушує розробників напружувати свій мозок, щоб вибрати відповідні імена для інтерфейсів. Обрані імена повинні відрізнятися не тільки префіксом, але й підкреслювати різницю намірів.
Випадок абстракції: ви не повинні визначати ICar
інтерфейс та пов'язаний Car
клас. Car
є абстракцією, і вона повинна бути тією, яка використовується для контракту. Реалізації повинні мати описові, відмінні назви, наприклад SportsCar, SuvCar, HollowCar
.
Хороший приклад: WpfeServerAutosuggestManager implements AutosuggestManager
, FileBasedAutosuggestManager implements AutosuggestManager
.
Поганий приклад: AutosuggestManager implements IAutosuggestManager
.
На своїй практиці я познайомився з багатьма людьми, які бездумно продублювали частину інтерфейсу класу в окремому інтерфейсі, маючи Car implements ICar
схему імен. Дублювання частини інтерфейсу класу в окремому типі інтерфейсу магічно не перетворює його в абстракцію. Ви все одно отримаєте конкретну реалізацію, але з дубльованою частиною інтерфейсу. Якщо ваша абстракція не така гарна, дублювання частини інтерфейсу все одно не покращить її. Видобування абстракції - це важка робота.
ПРИМІТКА. У TS вам не потрібен окремий інтерфейс для глузування класів або функцій перевантаження. Замість створення окремого інтерфейсу, що описує загальнодоступні члени класу, ви можете використовувати типи утиліт TypeScript . Наприклад, Required<T>
будує тип, що складається з усіх публічних членів типу T
.
export class SecurityPrincipalStub implements Required<SecurityPrincipal> {
public isFeatureEnabled(entitlement: Entitlement): boolean {
return true;
}
public isWidgetEnabled(kind: string): boolean {
return true;
}
public areAdminToolsEnabled(): boolean {
return true;
}
}
Якщо ви хочете створити тип, виключаючи деяких публічних членів, ви можете використовувати комбінацію Omit та Exclude .
I
префіксу має сенс для вас та вашої команди, ВИКОРИСТОВУЙТЕ. Якщо ні, можливо стиль JavaSomeThing
(інтерфейс) зSomeThingImpl
(реалізація), тоді неодмінно використовуйте це.