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

Управление несколькими способами оплаты является одним из самых сложных аспектов создания мобильного приложения. Каждый способ оплаты - будь то кредитные карты, PayPal, Apple Pay, Google Pay или региональные кошельки, такие как Alipay и WeChat Pay - поставляется с собственным API, правилами проверки, обработкой ошибок и требованиями соответствия. Добавление нового метода часто означает касание нескольких частей кодовой базы, введение риска и регрессии.

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

В этой статье мы рассмотрим, как применять заводской шаблон для управления различными способами оплаты в мобильных приложениях, с практическими примерами и лучшими практиками. Мы также обсудим, как этот шаблон согласуется с современными архитектурами, такими как MVVM и Clean Architecture, и как вы можете интегрировать его с бэкэнд-сервисами, такими как Directus, для хранения и извлечения конфигураций платежей динамически.

Понимание структуры завода

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

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

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

Как работает заводской шаблон

Обычно в схеме участвуют три участника:

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

Почему способы оплаты сложны в мобильных приложениях

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

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

Реализация фабричного шаблона способов оплаты

Пока примеры кода являются языковыми (псевдокод), мы будем использовать концепции, которые переводятся непосредственно в Swift, Kotlin, Flutter или React Native.

Шаг 1: Определите интерфейс платежного метода

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

interface PaymentMethod {
 func processPayment(amount: Double, currency: String) -> PaymentResult
 func validate() -> Bool
}

Вы также можете включить такие свойства, как , или , которые пользователь может использовать для отображения вариантов оплаты.

Шаг 2: Создание конкретных классов платежей

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

class CreditCardPayment : PaymentMethod {
 private let cardNumber: String
 private let expiry: String
 private let cvv: String

 init(cardNumber: String, expiry: String, cvv: String) {
 self.cardNumber = cardNumber
 self.expiry = expiry
 self.cvv = cvv
 }

 func validate() -> Bool {
 // Luhn check, expiry date > today, etc.
 return true // simplified
 }

 func processPayment(amount: Double, currency: String) -> PaymentResult {
 // Call Stripe or Braintree SDK
 return PaymentResult.success()
 }
}

class PayPalPayment : PaymentMethod {
 private let token: String

 init(token: String) {
 self.token = token
 }

 func validate() -> Bool {
 return !token.isEmpty
 }

 func processPayment(amount: Double, currency: String) -> PaymentResult {
 // Call PayPal SDK
 return PaymentResult.success()
 }
}

class ApplePayPayment : PaymentMethod {
 private let paymentData: Data

 init(paymentData: Data) {
 self.paymentData = paymentData
 }

 func validate() -> Bool {
 return paymentData.count > 0
 }

 func processPayment(amount: Double, currency: String) -> PaymentResult {
 // Use PassKit or Stripe Apple Pay integration
 return PaymentResult.success()
 }
}

Обратите внимание, что каждый конкретный класс обрабатывает свои собственные проверки и вызовы SDK. Остальная часть приложения не заботится о различиях - она только звонит .

Шаг 3: Постройте заводской класс

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

class PaymentFactory {

 static func createPaymentMethod(type: String, parameters: [String: Any]) -> PaymentMethod? {
 switch type {
 case "credit_card":
 guard let cardNumber = parameters["cardNumber"] as? String,
 let expiry = parameters["expiry"] as? String,
 let cvv = parameters["cvv"] as? String else {
 return nil
 }
 return CreditCardPayment(cardNumber: cardNumber, expiry: expiry, cvv: cvv)

 case "paypal":
 guard let token = parameters["token"] as? String else {
 return nil
 }
 return PayPalPayment(token: token)

 case "apple_pay":
 guard let paymentData = parameters["paymentData"] as? Data else {
 return nil
 }
 return ApplePayPayment(paymentData: paymentData)

 default:
 return nil
 }
 }
}

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

Шаг 4: Использование фабрики в вашем приложении

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

let paymentType = selectedPaymentMethod.type // "credit_card", "paypal", etc.
let parameters = collectInputParameters()
if let paymentMethod = PaymentFactory.createPaymentMethod(type: paymentType, parameters: parameters) {
 paymentMethod.processPayment(amount: total, currency: "USD")
} else {
 // show error – unsupported method or invalid input
}

Добавление нового способа оплаты (например, Google Pay) требует только нового класса и дополнительного случая в заявлении завода - никаких других изменений не требуется.

Вариации: специфичные для страны и динамические фабрики

В реальных приложениях набор доступных способов оплаты часто меняется в зависимости от страны пользователя, версии приложения или бизнес-правил. Можно сделать фабрику динамичной, подав ей объект конфигурации.

Suppose you use Directus to store enabled payment methods per region. Your backend returns a JSON object like this:

{
 "methods": ["credit_card", "paypal", "apple_pay"],
 "paypal": { "environment": "sandbox", "clientId": "abc123" }
}

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

class DynamicPaymentFactory {
 private let config: PaymentConfiguration

 init(config: PaymentConfiguration) {
 self.config = config
 }

 func createPaymentMethod(type: String, parameters: [String: Any]) -> PaymentMethod? {
 guard config.methods.contains(type) else { return nil }
 // Use config-specific parameters (e.g., clientId for PayPal)
 // ... switch as before
 }
}

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

Преимущества использования фабричного шаблона

К настоящему моменту преимущества должны быть понятны. Давайте перечислим их более подробно.

1. инкапсуляция создания объекта

Завод централизует логику инстанциации. Если конструктор класса оплаты изменяется (например, добавляется новый требуемый параметр), вы только обновляете завод и конкретный класс. Все абоненты остаются незатронутыми.

2.Соблюдение принципа открытости/закрытости

Ваш код открыт для расширения (добавление новых способов оплаты), но закрыт для модификации (существующие классы не меняются).

3.Упрощенное испытание установки

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

4.Усовершенствованная организация кода

Заводской шаблон естественным образом группирует связанные классы (методы оплаты) под общим интерфейсом. Это облегчает навигацию и понимание кодовой базы.

5. Гибкость во время выполнения

Вы можете объединить завод со стратегией или шаблоном для изменения поведения на основе условий выполнения, например, выбирая между тестовой и производственной средой.

6. Масштабируемость

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

Реальные мировые соображения

Интеграция с инъекцией зависимости

В современных мобильных архитектурах (MVVM, Clean Architecture, Viper) завод должен быть зарегистрирован в вашем контейнере для инъекций зависимостей. Таким образом, вы можете вводить в тесты реальный завод в производстве и макетный завод. Например, с помощью Dagger в Android или Swinject в iOS:

// Swift with Swinject
container.register(PaymentFactoryProtocol.self) { _ in PaymentFactory() }

Обработка ошибок и Fallbacks

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

Конфигурация из Backend (Directus)

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

Например, вы можете создать коллекцию в Directus с полями:

  • (струна: «credit card», «paypal»)
  • (струна)
  • (названия групп JSON)
  • (булеан)

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

Лучшие практики при использовании заводского шаблона

  • Сохранить фабрику простой. Она должна создавать только объекты. Если вы обнаружите, что добавляете бизнес-логику (например, конвертацию валюты), вычтите это в отдельные услуги.
  • Используйте сильную типизацию. Предпочитаете перечисления или запечатанные классы по строкам для типа метода. Это предотвращает ошибки во время выполнения от идентификаторов с ошибками орфографии и дает вам поддержку компилятора.
  • Документируйте интерфейс. Убедитесь, что все участники интерфейса имеют четкие контракты. Что именно делает ? Бросает или возвращает ошибку?
  • Проверить завод отдельно. Написать единичные тесты, которые проверяют, что завод возвращает правильный класс бетона для каждого ввода, и что он возвращает nil для неподдерживаемых типов.
  • Совместите с другими моделями. Завод хорошо работает с шаблоном Стратегии (для обработки различных потоков платежей) и шаблоном Строителя (если метод оплаты требует сложной конфигурации).
  • Рассматривайте реестр. Вместо монолитного переключателя можно построить открытый реестр, где классы способов оплаты регистрируются сами. Это распространено в архитектурах плагинов.

Заключение

Управление несколькими способами оплаты в мобильных приложениях не должно быть источником технического долга. Применяя заводской шаблон, вы инкапсулируете сложность создания объектов, делая вашу кодовую базу более чистой, более проверяемой и готовой к будущему расширению. Этот шаблон уважает принцип Open / Closed, отделяет бизнес-логику от сторонних SDK и плавно интегрируется с современными архитектурами и бэкэнд-сервисами, такими как Directus.

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

Дальнейшее чтение:
Паттер фабричных методов (Wikipedia)
Стрип-платеж Quickstart — мобильная интеграция
Сборники Directus и ссылки на API