La gestion de méthodes de paiement multiples est l'un des aspects les plus difficiles de la construction d'une application mobile. Chaque méthode de paiement – qu'il s'agisse de cartes de crédit, PayPal, Apple Pay, Google Pay ou portefeuilles spécifiques à une région comme Alipay et WeChat Pay – est livré avec sa propre API, les règles de validation, le traitement des erreurs et les exigences de conformité.

Le modèle d'usine offre une solution structurée à cette complexité. En centralisant la création d'objets de méthode de paiement, il découple le code client des implémentations concrètes de paiements. Cela rend votre application plus durable, testable et prêt à l'échelle comme de nouvelles options de paiement apparaissent inévitablement.

Dans cet article, nous allons explorer comment appliquer le modèle d'usine pour gérer différentes méthodes de paiement dans les applications mobiles, avec des exemples pratiques et des pratiques exemplaires. Nous allons également discuter comment ce modèle s'harmonise avec les architectures modernes comme MVVM et Clean Architecture, et comment vous pouvez l'intégrer avec les services de backend comme Directus pour stocker et récupérer dynamiquement les configurations de paiement.

Comprendre le modèle d'usine

Le modèle d'usine est un modèle de conception créative qui fournit une interface pour créer des objets dans une superclasse, mais permet aux sous-classes de modifier le type d'objets qui seront créés. En termes plus simples, il encapsule la logique d'instantiation de sorte que les clients n'ont pas besoin de connaître les classes de béton; ils interagissent seulement avec une interface commune.

Ce modèle est particulièrement précieux dans les applications mobiles où l'ensemble des méthodes de paiement peut croître au fil du temps. Sans une usine, vous pourriez finir avec de grandes ou déclarations dispersées sur votre base de code, chacun sachant construire une méthode de paiement spécifique. Cette approche viole le principe ouvert/fermé et rend le code rigide – l'ajout d'une nouvelle méthode de paiement nécessite de modifier chaque endroit qui en crée un.

Le modèle d'usine résout cela en plaçant toute la logique de création dans un seul endroit. Quand un nouveau mode de paiement est introduit, vous ajoutez simplement une nouvelle classe de béton et mettez à jour la méthode d'usine. Le reste de votre application reste inchangé.

Comment fonctionne le modèle d'usine

Le modèle comprend généralement trois participants :

  • Produit – Une interface ou une classe abstraite qui définit les opérations, toutes les méthodes de paiement doivent être supportées (p. ex. , .
  • Produits en béton – Catégories qui implémentent l'interface produit pour chaque méthode de paiement spécifique (p. ex., , .
  • Créateur (Factory)[ – Classe (ou fonction) qui contient une méthode de création de produits. La méthode accepte un paramètre (p. ex. une chaîne ou un enum) et renvoie le produit concret approprié.

Dans les applications mobiles, cette usine est souvent un service à simpleton ou à injection de dépendance, ce qui facilite l'échange d'implémentations lors des essais ou lors de l'assistance de différentes configurations d'applications.

Pourquoi les méthodes de paiement sont complexes dans les applications mobiles

Avant de plonger dans la mise en œuvre, il est utile de comprendre les points de douleur spécifiques que le modèle d'usine adresse. La gestion des paiements dans les applications mobiles va au-delà de simplement appeler une API.

  • – Chaque fournisseur de paiement offre sa propre API SDK ou REST. L'intégration directe de ces deux solutions dans votre logique commerciale crée un couplage serré.
  • Différences régionales et réglementaires – Un mode de paiement disponible dans un pays peut ne pas être autorisé dans un autre. Vous devrez peut-être choisir dynamiquement la configuration de l'usine en fonction de la localisation de l'utilisateur.
  • Règles de validation – Les cartes de crédit exigent des vérifications de Luhn et la validation de la date d'expiration; les portefeuilles numériques doivent être manipulés; les méthodes locales peuvent imposer des exigences spécifiques de champ.
  • Manipulation et replis d'erreurs – Lorsqu'un paiement échoue, l'application peut avoir besoin d'offrir une méthode alternative ou de réessayer avec différents paramètres. Une usine centralisée simplifie cette logique.
  • Testing – Vous ne voulez pas frapper les serveurs de paiement réel lors des tests unitaires. Le modèle d'usine vous permet d'injecter facilement des objets de paiement simulé.
  • Configuration dynamique – De nombreuses applications récupèrent les méthodes de paiement disponibles à partir d'un serveur distant (par exemple, de Directus).L'usine peut interpréter cette configuration pour créer les bons objets à l'exécution.

Compte tenu de ces défis, une abstraction bien conçue des paiements devient critique. Le modèle d'usine fournit cette couche d'abstraction.

Mise en œuvre du modèle d'usine pour les méthodes de paiement

Bien que les exemples de code soient language-agnostique (pseudocode), nous utiliserons des concepts qui se traduisent directement par Swift, Kotlin, Flutter ou React Native.

Étape 1: Définir l'interface de la méthode de paiement

Commencez par définir une interface commune que tous les modes de paiement doivent mettre en œuvre. Cette interface devrait comprendre des méthodes qui sont universelles pour tous les types de paiement, comme et .

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

Vous pouvez également inclure des propriétés comme , ou , que l'interface utilisateur peut utiliser pour afficher des options de paiement.

Étape 2: Créer des classes de paiement concrètes

Pour chaque méthode de paiement que vous supportez, créez une classe qui implémente l'interface . Ces classes encapsulent toute la logique spécifique au fournisseur.

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()
 }
}

Notez que chaque classe de béton gère ses propres appels de validation et SDK. Le reste de l'application ne se soucie pas des différences—il appelle seulement .

Étape 3: Construire la classe d'usine

La classe usine est responsable de la création de l'objet de méthode de paiement approprié basé sur les paramètres d'entrée. L'entrée peut provenir de la sélection de l'utilisateur, d'un objet de configuration ou d'une réponse du serveur (par exemple, de 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
 }
 }
}

Dans un scénario plus avancé, vous pouvez utiliser un enum au lieu d'une chaîne pour le type, ou vous pouvez charger la configuration de l'usine à partir d'une source distante. Le point clé est que l'usine est le seulement lieu où les classes de béton sont instanciées.

Étape 4: Utilisation de l'usine dans votre application

Maintenant, quand un utilisateur choisit un mode de paiement et fournit les détails nécessaires, votre modèle de vue ou contrôleur doit seulement appeler l'usine:

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
}

Ajouter un nouveau mode de paiement (par exemple, Google Pay) ne nécessite qu'une nouvelle classe et un cas supplémentaire dans l'état de l'usine – aucun autre changement n'est nécessaire.

Variations de manipulation : factories pays-spécifiques et dynamiques

Dans les applications du monde réel, l'ensemble des méthodes de paiement disponibles change souvent en fonction du pays de l'utilisateur, de la version de l'application ou des règles d'affaires.

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" }
}

Vous pouvez stocker cette configuration dans un dépôt ou dans votre application. Ensuite, l'usine peut la lire à l'exécution:

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
 }
}

Cette approche maintient votre application adaptable sans nécessiter une nouvelle version de l'application pour chaque changement de fournisseur de paiement.

Avantages de l'utilisation du modèle d'usine

Les avantages devraient être clairs. Laissez-les énumérer plus en détail.

1. Encapsulation de la création d'objets

Si le constructeur d'une classe de paiement change (par exemple, un nouveau paramètre est ajouté), vous ne mettez à jour l'usine et la classe de béton. Tous les appelants restent inchangés.

2. Respect du principe ouvert/fermé

Votre code est ouvert pour l'extension (ajout de nouvelles méthodes de paiement) mais fermé pour modification (les classes existantes ne changent pas). Cela réduit le risque d'introduire des bogues dans les flux de paiement déjà testés.

3. Essais simplifiés en unité

Parce que l'usine peut être moquée ou remplacée, vous pouvez facilement injecter des objets de paiement faux lors des tests. Par exemple, vous pouvez créer un qui retourne toujours un paiement réussi sans toucher au réseau.

4. Organisation améliorée du code

Le modèle d'usine regroupe naturellement les classes liées (méthodes de paiement) sous une interface commune, ce qui facilite la navigation et la compréhension de la base de données.

5. Flexibilité du temps de fonctionnement

Vous pouvez combiner l'usine avec une stratégie ou un modèle pour modifier le comportement en fonction des conditions d'exécution, par exemple, en choisissant entre un environnement de test et de production.

6. Écailabilité

Chaque nouvelle méthode est un fichier séparé, et le commutateur d'usine reste linéaire.

Considérations du monde réel

Intégration avec injection de dépendance

Dans les architectures mobiles modernes (MVVM, Clean Architecture, Viper), l'usine doit être enregistrée dans votre conteneur d'injection de dépendance. De cette façon, vous pouvez injecter une véritable usine dans la production et une usine de simulation dans les tests. Par exemple, utiliser Dagger dans Android ou Swinject dans iOS:

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

Gestion des erreurs et des chutes

Votre usine doit gérer les entrées invalides gracieusement. Retourner ] ou lancer un type d'erreur spécifique permet à l'appelant de présenter une interface utilisateur significative. De même, vous pouvez implémenter une usine de repli qui par défaut à une méthode de paiement universel si la demande ne parvient pas à initialiser.

Configuration depuis le moteur de recherche (Directus)

Directus peut être utilisé pour stocker les métadonnées de méthodes de paiement, comme l'affichage de l'ordre, les champs requis, ou même les règles de validation personnalisées. Votre application mobile récupère cette configuration au démarrage et la transmet à l'usine.

Par exemple, vous pourriez créer une collection dans Directus avec des champs :

  • (chaîne: "credit card", "paypal")
  • (chaîne)
  • (Tableau JSON des noms de champs)
  • (booléenne)

Votre application mobile récupère cette collection via le Directus SDK et construit le registre d'usines dynamiquement. Ce modèle permet aux parties prenantes non-développeurs de contrôler les offres de paiement sans changement de code.

Meilleures pratiques lors de l'utilisation du modèle d'usine

  • Gardez l'usine simple. Elle ne devrait créer que des objets. Si vous vous trouvez à ajouter une logique d'affaires (p. ex., conversion de devises), extraire cela dans des services distincts.
  • Utilisez une forte frappe. Préférez des enums ou des classes scellées sur des chaînes pour le type de méthode. Cela empêche les erreurs d'exécution des identifiants mal orthographiés et vous donne le support du compilateur.
  • Documenter l'interface. S'assurer que tous les membres de l'interface ont des contrats clairs. Que fait exactement? lance-t-il ou renvoie une erreur?
  • Testez l'usine séparément. Écrire des tests unitaires qui vérifient que l'usine retourne la classe de béton correcte pour chaque entrée, et qu'elle retourne zéro pour les types non pris en charge.
  • Combiner avec d'autres modèles L'usine fonctionne bien avec le modèle de stratégie (pour gérer différents flux de paiement) et le modèle de constructeur (si une méthode de paiement nécessite une configuration complexe).
  • Considérer un registre. Au lieu d'un commutateur monolithique, vous pouvez construire un registre ouvert où les classes de méthodes de paiement s'enregistrent.

Conclusion

La gestion de plusieurs méthodes de paiement dans les applications mobiles n'est pas nécessairement une source de dettes techniques. En appliquant le modèle d'usine, vous encapsulez la complexité de la création d'objets, rendant votre base de code plus propre, plus testable et prêt pour l'expansion future. Le modèle respecte le principe ouvert/fermé, découple la logique commerciale des SDK tiers, et s'intègre en douceur avec les architectures modernes et les services de backend comme Directus.

Lorsque vous faites face à une liste croissante d'options de paiement, atteindre le modèle d'usine. Il vous fera gagner du temps, réduire les bogues, et vous laisser ajouter de nouvelles méthodes de paiement avec confiance.


- Modèle de méthode de la dynamique (Wikipedia)[
- Stripe Payment Quickstart – intégration mobile
- Directus Collections et API Référence