Представим, что мы пишем приложение, которое отображает сообщения пользователей в режиме бесконечной прокрутки. Мы имеем дело с тремя различными конкретными типами сообщений:

Первый подход может заключаться в создании структуры для каждого из трех типов, выделении общих полей в их собственную структуру и использовании композиции. Но в этом случае у нас не останется абстрактного супертипа, что сделает невозможным объединение постов в коллекцию или использование полиморфизма.

Следовательно, нам нужно искать другое решение. Сначала мы начнем с определения структуры для общих полей:

Теперь нам нужно найти способ хранения дополнительных данных, специфичных для каждого типа сообщений, и нам нужно добиться этого таким образом, чтобы он был как типобезопасным, так и взаимоисключающим. В языке C есть конструкция под названием union, которая была разработана для выполнения именно этой работы, и хотя union не встроен в Swift, то же самое поведение может быть разумно достигнуто с помощью enum.

Сначала мы создаем структуры для хранения определенных данных:

Затем мы определяем следующее перечисление:

И, наконец, мы используем его в SocialMediaPost:

Теперь все, что нам нужно сделать, это создать инициализаторы для каждого типа публикации, и мы готовы:

Реализация бизнес-логики

Представим, что мы хотим отображать сообщения наших пользователей в веб-просмотре. Для этого нам нужно отформатировать их как HTML.

Сначала мы объявляем protocol для метода, который хотим выполнить рендеринг HTML:

Затем мы реализуем этот протокол в каждой из наших структур и перечислений, используя расширения:

Наконец, мы можем проверить, что наш код ведет себя так, как ожидалось:

И, как и ожидалось, он делает это и печатает:

Заключение

На первый взгляд наследование может выглядеть как серебряная пуля, которая изящно обрабатывает все случаи, когда код необходимо исключить. Но если мы посмотрим глубже, мы увидим, что значительную часть того, что он приносит, можно на самом деле воспроизвести с помощью композиции.

В этой статье описывается одна возможная реализация, использующая перечисления, но возможны и другие варианты. Например, эта площадка показывает, как этого можно достичь с помощью протокольно-ориентированного программирования.

Вам понравилась эта статья, и вы хотите видеть больше подобного контента? Не стесняйтесь подписываться на меня в Twitter: https://twitter.com/v_pradeilles