So, during my interview taking sessions that I engage in almost daily, I have been asking a common question these days, that takes into account not just Object-oriented design but also caters to various design patterns available.
Suppose you have to design a payment system, which caters to different payment types available for the user like Credit Card, Debit Card, Internet Banking or UPI etc. How shall you put forth the low-level design of this system?
So for this problem, you can define a common base interface, lets call it Payments, having a single method pay(). Here we make of Java to create our classes and interfaces.
@FunctionalInterfaceinterface Payments{ boolean pay(PaymentDetails detail);}
Using this Payments interface we shall build our different payment type classes, providing the definition for the pay() method as per the chosen payment type. Let’s take the CreditCard as an example and build the class structure for it.
class CreditCardPayment implements Payments{ public boolean pay(PaymentDetails detail){ //Actual implementation for Credit Card related payments }}
Similarly for other classes. To elaborate this class construction here, it specifically makes use of Strategy Design pattern, as shown in figure below

Strategy pattern is a behavioral design pattern, where a strategy represents a way of doing a specific thing. Different strategies represent different ways of doing a thing, based on differing context. In our case, if user wants to do a Credit card payment, we will make use of CreditCard payment class/strategy, if user wants to make use of DebitCard payment then he shall make use of DebitCard payment class/strategy and accordingly for others.
Having said let’s increase our requirements. Let’s say there is a payment verification service, that must be called before making any payment which let’s say does a payment verification using the details of the payment and it is a common functionality that must available to all implementing classes. How shall we about to incorporate this requirement ? So two options come to my mind here:
- Making use of a default method inside Payments interface.
- Making use of an abstract class.
Lets see a sample code for both the cases:
Use of default method
interface Payments{ boolean pay(); //Default Method in the Payments Interface public default void verify(){ //Steps to verify the payment }}
Use of Abstract class
abstract class AbstractPayments implements Payments{ //Method to verify payments. public default void verify(){ //Steps to verify the payment }}
The use of this module shall instantiate a specific implementation based on his needs and would initiate the payments using the pay() method definition in that class.
public enum PaymentType { CREDIT_CARD, DEBIT_CARD, PAYPAL, BANK_TRANSFER, CASH, UPI}class PaymentService{ Payments payments; public PaymentService(Enum PaymentType){ switch (type) { case CREDIT_CARD: System.out.println("Processing Credit Card payment..."); payments = CreditCardPayment(); break; case DEBIT_CARD: System.out.println("Processing Debit Card payment..."); payments = DebitCardPayment(); break; case PAYPAL: System.out.println("Processing PayPal payment..."); payments = PaypalPayment(); break; case BANK_TRANSFER: System.out.println("Processing Bank Transfer..."); payments = BankTransferPayment(); break; case CASH: System.out.println("Processing Cash payment..."); payments = CashPayment(); break; case UPI: System.out.println("Processing UPI payment..."); payments = UPIPayment(); break; default: System.out.println("Unknown payment type!"); } } public boolean pay(PaymentDetails detail){ boolean wasPaymentSuccessful = payments.pay(detail); //other piece of code }}
This way we can make use of Strategy Design pattern to implement various payment strategies and accordingly structure our low-level class code for the payments module.
In the next continuing blog for this, we shall add some more real time requirement to this payment module, that shall make it even exciting to design.
Code for the entire payment’s module is available at the following GitHub repo.