Introduction
When integrating multiple payment methods (Online, POS, and Payment Links), maintaining a flexible and scalable architecture is crucial. The Factory Design Pattern allows us to dynamically create payment processors based on the given type. In this blog, we’ll explore how to implement it efficiently.
Understanding Payment Methods
Before diving into the code, let's quickly define the three main payment types:
- Payment Gateway (PG): Handles online payments directly through services like Razorpay, Paytm, or CashFree.
- Point of Sale (POS): In-store payment processing through card machines.
- Payment Links: Allows merchants to send payment links for remote transactions. ## Step 1: Define Payment Processors ### Online Payment Processors
class RazorpayPG {
process() { console.log("Processing Razorpay PG Payment"); }
}
class PaytmPG {
process() { console.log("Processing Paytm PG Payment"); }
}
class CashFreePG {
process() { console.log("Processing CashFree PG Payment"); }
}
POS Payment Processors
class PaytmPOS {
process() { console.log("Processing Paytm POS Payment"); }
}
class RazorpayPOS {
process() { console.log("Processing Razorpay POS Payment"); }
}
class CashFreePOS {
process() { console.log("Processing CashFree POS Payment"); }
}
Payment Link Processors
class RazorpayLink {
generate() { console.log("Generating Razorpay Payment Link"); }
}
class PaytmLink {
generate() { console.log("Generating Paytm Payment Link"); }
}
class CashFreeLink {
generate() { console.log("Generating CashFree Payment Link"); }
}
Step 2: Implement the Factory Class
Now, let’s create a Factory Class that will dynamically generate the required payment processor.
class PaymentFactory {
static createPayment(type, provider) {
// Mapping payment types to their respective classes
const paymentTypes = {
online: { razorpay: RazorpayPG, paytm: PaytmPG, cashfree: CashFreePG },
pos: { razorpay: RazorpayPOS, paytm: PaytmPOS, cashfree: CashFreePOS },
paymentLink: { razorpay: RazorpayLink, paytm: PaytmLink, cashfree: CashFreeLink },
};
// Validate type and provider
if (!paymentTypes[type] || !paymentTypes[type][provider]) {
throw new Error("Invalid payment type or provider");
}
return new paymentTypes[type][provider]();
}
}
Step 3: Using the Factory Pattern
Now, we can dynamically create payment instances based on the payment type.
// Example 1: Processing an Online Payment with Razorpay
const payment1 = PaymentFactory.createPayment("online", "razorpay");
payment1.process(); // Output: Processing Razorpay PG Payment
// Example 2: Processing a POS Payment with Paytm
const payment2 = PaymentFactory.createPayment("pos", "paytm");
payment2.process(); // Output: Processing Paytm POS Payment
// Example 3: Generating a Payment Link via CashFree
const payment3 = PaymentFactory.createPayment("paymentLink", "cashfree");
payment3.generate(); // Output: Generating CashFree Payment Link
How the Factory Pattern Works
✅ Step-by-Step Flow:
1️⃣ User requests a payment method (online
, pos
, or paymentLink
).
2️⃣ The Factory Class selects the correct provider (razorpay
, paytm
, cashfree
).
3️⃣ The corresponding class instance is created dynamically.
4️⃣ The process()
or generate()
function is executed based on the type.
Advantages of Using the Factory Pattern
✅ Scalability: Easily add new payment methods without modifying existing code.
✅ Maintainability: Reduces duplicate code and centralizes payment processing logic.
✅ Flexibility: Dynamically selects the correct payment class based on input parameters.
Final Thoughts
Using the Factory Design Pattern simplifies managing multiple payment integrations in your application. With this approach, you can easily scale and modify the system without breaking existing functionality.
Let me know in the comments if you have any questions or suggestions! 🚀
Top comments (0)