The refactored code uses the Adapter Pattern (also called the Wrapper Pattern). The new RazorpayAdapter closes the gap between our own PaymentGateway interface and the incompatible third-party RazorpayAPI.
1. Key Improvements
Open/Closed Principle (OCP)
The Benefit: We added a new payment provider without editing the existing CheckoutService code.
The Impact: The system is open for extension (add new adapters) but closed for modification (the core business logic stays untouched).
Translation Encapsulation
The Benefit: The messy details of mapping orderId to invoiceId and pay() to makePayment() are hidden inside the Adapter.
The Impact: CheckoutService stays "clean". It only uses its own words, such as orderId and pay().
Single Responsibility
The Benefit: The RazorpayAdapter has one job: converting one interface to another.
The Impact: This keeps vendor-specific logic and data conversions out of CheckoutService.
2. Structural Breakdown
Component
Responsibility
Target (PaymentGateway)
The interface our own code defines and the client uses.
Client (CheckoutService)
Works with any object that follows the Target interface.
Adaptee (RazorpayAPI)
The existing class that needs adapting (the third-party code).
Adapter (RazorpayAdapter)
Wraps the Adaptee so it looks like the Target.
3. Comparison of "Before" vs "After"
Feature
Before (Incompatible)
After (Adapter Pattern)
Interoperability
CheckoutService cannot use RazorpayAPI.
CheckoutService uses RazorpayAPI via the adapter.
Client Changes
Required to support new APIs.
Zero changes required to the client.
Third-Party Code
Might require modification (often impossible).
Used as-is, wrapped by the adapter.
Maintenance
High risk when switching vendors.
Low risk; just swap the adapter instance.
4. Summary of the "Adapter"
The Adapter Pattern is a translator. Just as a travel adapter lets an Indian plug work in a European socket, the RazorpayAdapter allows the RazorpayAPI to "plug in" to the CheckoutService.
1package DesignPatterns.StructuralPatterns.AdapterDesignPattern.After;23/**4 * 1. TARGET INTERFACE5 * This defines the "domain-specific" interface that the Client (CheckoutService) uses.6 */7interface PaymentGateway {8 void pay(String orderId, double amount);9}1011/**12 * 2. COMPATIBLE IMPLEMENTATION13 * A standard implementation that already follows our internal contract.14 */15class PayUGateway implements PaymentGateway {1617 @Override18 public void pay(String orderId, double amount) {19 System.out.println(20 "Paid Rs. " + amount + " using PayU for order: " + orderId21 );22 }23}2425/**26 * 3. ADAPTEE (The External Legacy/Third-Party System)27 * This class has the functionality we need, but its interface is incompatible28 * with our PaymentGateway (different method names/parameters).29 */30class RazorpayAPI {3132 public void makePayment(String invoiceId, double amountInRupees) {33 System.out.println(34 "Paid Rs. " +35 amountInRupees +36 " using Razorpay for invoice: " +37 invoiceId38 );39 }40}4142/**43 * 4. THE ADAPTER44 * This is the "Wrapper." It implements the Target interface and delegates45 * the work to the Adaptee (RazorpayAPI).46 */47class RazorpayAdapter implements PaymentGateway {4849 private RazorpayAPI razorpayAPI;5051 public RazorpayAdapter() {52 this.razorpayAPI = new RazorpayAPI();53 }5455 /**56 * TRANSLATION LAYER:57 * This method maps our standard 'pay()' call to the third-party 'makePayment()' call.58 */59 @Override60 public void pay(String orderId, double amount) {61 // We translate orderId -> invoiceId and amount -> amountInRupees62 razorpayAPI.makePayment(orderId, amount);63 }64}6566/**67 * 5. CLIENT68 * Stays 100% decoupled. It doesn't know (or care) if it's talking to69 * PayU directly or to Razorpay via an Adapter.70 */7172class CheckoutService {7374 private PaymentGateway paymentGateway;7576 public CheckoutService(PaymentGateway paymentGateway) {77 this.paymentGateway = paymentGateway;78 }7980 public void checkout(String orderId, double amount) {81 paymentGateway.pay(orderId, amount);82 }83}8485class Main {8687 public static void main(String[] args) {88 // SUCCESS: We can now plug the 'Adapter' into the 'Service'.89 // This follows the Open/Closed Principle: We added Razorpay90 // without modifying the CheckoutService class.91 CheckoutService checkoutService = new CheckoutService(92 new RazorpayAdapter()93 );9495 checkoutService.checkout("12", 1780);96 }97}98