CheckoutService depends directly on concrete classes like RazorpayGateway and GSTInvoice.
The Issue: The high-level business logic knows low-level details, such as which gateway class to build.
The Impact: To change a provider, you must edit the core checkout logic.
2. Violation of Open/Closed Principle (OCP)
The code is not "closed for modification" (you cannot add features without editing it).
The Issue: Each new payment method (e.g., Stripe, PayPal) means opening CheckoutService.java and adding another if-else or switch block.
The Impact: Editing a core service class again and again makes it easy to break logic that already works.
3. Lack of Object "Families"
The Abstract Factory pattern exists to create families of related objects, objects that must match each other.
The Issue: The code creates the PaymentGateway and the Invoice separately. Nothing in the structure says they "belong" together.
The Scenario: If you expand to the USA, you need a PayPalGateway AND a USInvoice (the classes the After code uses). Nothing stops the code from pairing a RazorpayGateway (India) with a USInvoice (USA). That would be a business logic error.
4. Maintenance Rigidity
As regions and providers grow, the checkOut method turns into a "God Method" (one method that does too much). It fills up with conditions that decide which objects to create.
Summary of the "Smell"
If you see if/else deciding which concrete class to create, move that job to a Factory.
1package DesignPatterns.CreationalPatterns.AbstractFactoryDesignPattern.Before;23// 1. Product Interface for Payments4interface PaymentGateway {5 void processPayment(double amount);6}78// Concrete Product A19class RazorpayGateway implements PaymentGateway {1011 public void processPayment(double amount) {12 System.out.println("Processing INR payment via Razorpay: " + amount);13 }14}1516// Concrete Product A217class PayUGateway implements PaymentGateway {1819 public void processPayment(double amount) {20 System.out.println("Processing INR payment via PayU: " + amount);21 }22}2324// 2. Product Interface for Invoices25interface Invoice {26 void generateInvoice();27}2829// Concrete Product B130class GSTInvoice implements Invoice {3132 public void generateInvoice() {33 System.out.println("Generating GST Invoice for India.");34 }35}3637/**38 * PROBLEM: The "God Class" that creates its own dependencies.39 * This class handles both the BUSINESS logic (checkout) and the CREATION logic (new keyword).40 */41class CheckoutService {4243 private String gatewayType;4445 public CheckoutService(String gatewayType) {46 this.gatewayType = gatewayType;47 }4849 public void checkOut(double amount) {50 PaymentGateway paymentGateway;5152 // PROBLEM 1: Tight Coupling & "If-Else" Hell53 // If we add a 3rd gateway (e.g., Stripe), we MUST modify this class.54 // This violates the Open/Closed Principle.55 if (gatewayType.equals("razorpay")) {56 paymentGateway = new RazorpayGateway();57 } else {58 paymentGateway = new PayUGateway();59 }6061 paymentGateway.processPayment(amount);6263 // PROBLEM 2: Lack of Cohesion (Families of objects)64 // What if we expand to the US? We would need a 'TaxInvoice' instead of 'GSTInvoice'.65 // Currently, we are hard-coding GSTInvoice here. There is no way to ensure the66 // PaymentGateway and Invoice "match" as a family.67 Invoice invoice = new GSTInvoice();68 invoice.generateInvoice();69 }70}7172class Main {7374 public static void main(String[] args) {75 CheckoutService razorpayService = new CheckoutService("razorpay");76 razorpayService.checkOut(1500.00);77 }78}79