Использование запечатанных классов для упрощения сложных потоков данных

Вступление

Управление состоянием - один из важнейших аспектов любой платформы во время роста продукта.

Одно из моих приложений в магазине Google Play имеет платежный экран с несколькими платежными шлюзами. Пользователи могут производить оплату через любой шлюз.

После оплаты появится всплывающее окно с подтверждением о статусе покупки.

Проблема

Вначале у нас был только Google Play Billing (для покупок в приложении). В то время было легко поддерживать такие состояния, как success, failure, retry и acknowledgment. Недавно мы решили добавить PayU и Stripe в качестве дополнительных платежных шлюзов, и здесь началась проблема управления состоянием.

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

Именно тогда мы нашли отличный доклад (ресурс добавлен в конце статьи) Патрика Казинса на Kotlin Conference 2018 о запечатанных классах и о том, как он использовал их для поддержания состояний во время входа в свое приложение.

Решение

Итак, мы убеждены, что нам нужно заняться государственным управлением закрытыми классами. Прежде чем обсуждать, как мы это реализовали, вы должны узнать о запечатанных классах.

Определение из Котлина

«Запечатанные классы используются для представления иерархий ограниченных классов, когда значение может иметь один из типов из ограниченного набора, но не может иметь другой тип. В некотором смысле они являются расширением классов перечисления: набор значений для типа перечисления также ограничен, но каждая константа перечисления существует только как единственный экземпляр, тогда как подкласс запечатанного класса может иметь несколько экземпляров, которые могут содержать штат."

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

Теперь давайте посмотрим на простой пример использования запечатанных классов. Ниже показан запечатанный класс для поддержания состояний при инициировании сетевого запроса. Здесь есть два состояния: Loading и Error.

Loading: это состояние возвращает логическое значение, если отображается истинная загрузка, в противном случае оно скрыто.
Error: Это состояние возвращает сообщение об ошибке в виде строки. При возникновении ошибки загрузка скрывается и появляется всплывающее окно с сообщением об ошибке.

Теперь, с другой стороны, мы должны использовать оператор when в Kotlin для работы с различными состояниями, как показано ниже.

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

Здесь мы должны выполнять вызовы API в двух местах:

  1. Чтобы сделать покупку.
  2. Чтобы подтвердить покупку, если она успешна.

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

Затем, если покупка прошла успешно, мы должны подтвердить покупку и показать результат пользователю во всплывающем окне. Для состояний потока подтверждений мы создали следующий класс:

Эти два закрытых класса могут иметь дело с потоками покупок и подтверждений всех платежных шлюзов. Но раньше мы держали все классы в одном классе, как древовидную структуру. Посмотри:

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

В нашем случае это кажется лучше, потому что у нас есть функции, специфичные для шлюза, которые необходимо запускать.

Но мы также можем поддерживать запечатанные классы по-разному, без какой-либо древовидной структуры в одном файле, как показано выше.

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

Это простой способ заставить его работать, когда у вас нет дел, связанных с конкретным шлюзом. Будьте прагматичны и выберите то, что вам подходит.

Полезные ссылки