A simple and extensible Payment Processing System built using the Spring Framework (Core + Dependency Injection). This project demonstrates how to use Factory Design Pattern + Spring’s Dependency Injection to dynamically select and process different payment methods.
-
Supports multiple payment types:
- UPI
- Credit Card
- Debit Card
-
Uses Spring Annotation-based Configuration
-
Implements Factory Design Pattern
-
Easily extendable for new payment methods
-
Clean and modular architecture
- Spring IoC Container
- Dependency Injection (DI)
- Component Scanning
- Factory Design Pattern
- Interface-based programming
com.nit
│
├── config
│ └── AppConfig.java
│
├── main
│ └── TestApp.java
│
└── sbeans
├── Payment.java
├── PaymentFactory.java
├── CreditCardPayment.java
├── DebitCardPayment.java
└── UPIPayment.java
Spring configuration class with component scanning:
@Configuration
@ComponentScan(basePackages="com.nit.sbeans")
public class AppConfig {
}public interface Payment {
String pay(double amount);
}@Component("credit")
public class CreditCardPayment implements Payment {
public String pay(double amount) {
double discount = 10;
double finalAmount = amount - (amount * discount);
return "Paid " + finalAmount + " using Credit Card";
}
}@Component("debit")
public class DebitCardPayment implements Payment {
public String pay(double amount) {
double discount = 5;
double finalAmount = amount - (amount * discount);
return "Paid " + finalAmount + " using Debit Card";
}
}@Component("upi")
public class UPIPayment implements Payment {
public String pay(double amount) {
double discount = 15;
double finalAmount = amount - (amount * discount);
return "Paid " + finalAmount + " using UPI";
}
}Handles dynamic selection of payment method using Spring's auto-wired map:
@Component
public class PaymentFactory {
@Autowired
private Map<String, Payment> paymentMap;
public Payment getPayment(String type) {
Payment payment = paymentMap.get(type.toLowerCase());
if (payment == null) {
throw new IllegalArgumentException("Invalid Payment Type");
}
return payment;
}
}public class TestApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
PaymentFactory paymentFactory = ctx.getBean(PaymentFactory.class);
try {
Payment payment = paymentFactory.getPayment("upi");
System.out.println(payment.pay(50000));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}Paid -700000.0 using UPI
(Note: Discount calculation currently multiplies instead of percentage — can be improved)
- Spring scans all
@Componentclasses. - Each payment method is registered with a unique name (
credit,debit,upi). - Spring injects all implementations into a
Map<String, Payment>. PaymentFactoryselects the correct implementation dynamically.TestApptriggers the payment process.
- Fix discount calculation logic (use percentage properly)
- Add new payment methods (Net Banking, Wallets)
- Add logging (SLF4J / Log4j)
- Add REST API layer (Spring Boot)
- Add unit testing (JUnit)
This project shows how Spring + Factory Pattern can eliminate complex if-else or switch statements and make the system clean, scalable, and maintainable.
Built as a learning project for understanding Spring Core concepts and design patterns.
Give it a ⭐ on GitHub and keep building 🚀