Инкапусляция на практике
Прогаем на уровне интерфейсов, а не реализации.
Это значит, что детали реализации нужно оборачивать в абстракции и выстраивать взаимодействие между ними.
Например, для API чата напишем класс MessageObesrver.
- Придумаем, как класс будет взаимодействовать с приложением: что возвращают публичные методы, какие аргументы принимают.
- Выделим приватные поля и методы, где напишем реализацию с помощью, например, SocketIO.
- Опишем публичные методы, которые будут с ней работать. В них не должно быть ничего от конкретной реализации - они должны дергать приватные поля и методы.
С таким классом мы сможем легко заменить библиотеку или подправить код реализации, не меняя ничего в приложении. Класс оказывается чёрным ящиком с неизменным интерфейсом.
В SOLID это - буква "D": dependency inversion principle (принцип инверсии зависимостей).
#инкапсуляция #паттерны #SOLID
Прогаем на уровне интерфейсов, а не реализации.
Это значит, что детали реализации нужно оборачивать в абстракции и выстраивать взаимодействие между ними.
Например, для API чата напишем класс MessageObesrver.
- Придумаем, как класс будет взаимодействовать с приложением: что возвращают публичные методы, какие аргументы принимают.
- Выделим приватные поля и методы, где напишем реализацию с помощью, например, SocketIO.
- Опишем публичные методы, которые будут с ней работать. В них не должно быть ничего от конкретной реализации - они должны дергать приватные поля и методы.
С таким классом мы сможем легко заменить библиотеку или подправить код реализации, не меняя ничего в приложении. Класс оказывается чёрным ящиком с неизменным интерфейсом.
В SOLID это - буква "D": dependency inversion principle (принцип инверсии зависимостей).
#инкапсуляция #паттерны #SOLID
Open Close principe
Еще один принцип проектирования - отделение изменяемых частей приложения от неизменяемых. Неизменяемая часть не должная изменяться, будучи полностью абстрактной. При этом она должна быть открыта к использованию в максимальном количестве сценариев.
Например, есть задача сделать модальное окно.
Разделим его на две условные части:
- Контейнер с полупрозрачным оверлеем
- Область контента
Создадим для контейнера отдельный компонент, который ничего не будет знать о контенте. Постараемся предусмотреть возможную модификацию: например, компонент будет принимать объект пропов с настройками прозрачности оверлея, размеров и положения на экране. Оставим его опциональным.
Создадим компонент контента и пробросим в модальное окно.
С такой архитектурой компонент модального окна будет легко переиспользован в проекте.
#паттерны #SOLID
Еще один принцип проектирования - отделение изменяемых частей приложения от неизменяемых. Неизменяемая часть не должная изменяться, будучи полностью абстрактной. При этом она должна быть открыта к использованию в максимальном количестве сценариев.
Например, есть задача сделать модальное окно.
Разделим его на две условные части:
- Контейнер с полупрозрачным оверлеем
- Область контента
Создадим для контейнера отдельный компонент, который ничего не будет знать о контенте. Постараемся предусмотреть возможную модификацию: например, компонент будет принимать объект пропов с настройками прозрачности оверлея, размеров и положения на экране. Оставим его опциональным.
Создадим компонент контента и пробросим в модальное окно.
С такой архитектурой компонент модального окна будет легко переиспользован в проекте.
#паттерны #SOLID
Принцип подстановки Барбары Лисков
Всю ночь раскидывал мозгами над этим принципом. И, кажется, понял. 💡
Он весь о наследовании. Не обязательно в терминологии ООП.
Любая сущность, которая является подтипом некоей более общей сущности, при подстановке на место расширяемой сущности должна работать так же, как и расширяемая сущность.
Для кода, использовавшего предыдущую сущность, ничего не должно измениться.
За пример во фронтенде можно взять кнопки в UI-ките. Мы создаем компонент кнопки, содержащий общие стили, а затем "наследуем" от него подвиды кнопок. При замене кнопок мы не должны перетряхивать весь код вокруг них. В идеале для кода окружения кнопок измениться не должно вообще ничего.
Другой пример - разработка API. Внезапно на этом слое понадобилось реализовать кэширование. Мы наследуемся от существующего класса, допиливаем функциональность, распространяем новый класс по системе... И ничего больше в ней не меняем. Методы API работают как раньше.
Строгость следования этому принципу - вопрос открытый.
#SOLID
Всю ночь раскидывал мозгами над этим принципом. И, кажется, понял. 💡
Он весь о наследовании. Не обязательно в терминологии ООП.
Любая сущность, которая является подтипом некоей более общей сущности, при подстановке на место расширяемой сущности должна работать так же, как и расширяемая сущность.
Для кода, использовавшего предыдущую сущность, ничего не должно измениться.
За пример во фронтенде можно взять кнопки в UI-ките. Мы создаем компонент кнопки, содержащий общие стили, а затем "наследуем" от него подвиды кнопок. При замене кнопок мы не должны перетряхивать весь код вокруг них. В идеале для кода окружения кнопок измениться не должно вообще ничего.
Другой пример - разработка API. Внезапно на этом слое понадобилось реализовать кэширование. Мы наследуемся от существующего класса, допиливаем функциональность, распространяем новый класс по системе... И ничего больше в ней не меняем. Методы API работают как раньше.
Строгость следования этому принципу - вопрос открытый.
#SOLID
Принцип разделения интерфейсов
Он же Interface segregation principle.
В чем его суть?
Зайду с двух сторон.
Представим код на TypeScript. Дана сущность "Юзер", делящаяся по возможностям на "Пользователь", "Модератора" и "Админа". Её описывает общий интерфейс, содержащий методы для всех подтипов. Но это не имеет смысла: реализуя этот интерфейс, пользователь должен будет содержать пустой метод возможности админа. Либо методы админа будут опциональными - что лишит типизацию строгости. Чтобы этого избежать, разделим "толстый" интерфейс на три более узких и прокинем все в сущность через логическое "или".
Интерфейс - это не только сущность TS. Это часть кода, выставленная наружу для использования. Плохой интерфейс предоставляет слишком много методов - раздувается бандл, увеличивается зависимость программы от этого кода. А хороший предоставляет минимально возможный интерфейс.
Принцип разделения интерфейсов, следовательно, о разделении кода и избавлении от лишних зависимостей.
#SOLID
Он же Interface segregation principle.
В чем его суть?
Зайду с двух сторон.
Представим код на TypeScript. Дана сущность "Юзер", делящаяся по возможностям на "Пользователь", "Модератора" и "Админа". Её описывает общий интерфейс, содержащий методы для всех подтипов. Но это не имеет смысла: реализуя этот интерфейс, пользователь должен будет содержать пустой метод возможности админа. Либо методы админа будут опциональными - что лишит типизацию строгости. Чтобы этого избежать, разделим "толстый" интерфейс на три более узких и прокинем все в сущность через логическое "или".
Интерфейс - это не только сущность TS. Это часть кода, выставленная наружу для использования. Плохой интерфейс предоставляет слишком много методов - раздувается бандл, увеличивается зависимость программы от этого кода. А хороший предоставляет минимально возможный интерфейс.
Принцип разделения интерфейсов, следовательно, о разделении кода и избавлении от лишних зависимостей.
#SOLID