vendredi 5 novembre 2021

Designing payment gateway system

Context: I am trying to design a payment gateway system in which clinet decides its desired method and partner, the system returns appropriate interface. Let's just assume my company has two ways of making payment: (1) through vendors, (2) through our own branch if we have local presence. Now, we have VendorPayment, and LocalBranchPayment.

Since we don't have full control with VendorPayment, I've only able to come up with limited methods. For example, VendorPayment offers following methods: (1) Pay, (2) CheckStatus, (3) Fund. On the other hand, we have more control with LocalPayment: (1) Pay, (2) CheckStatus, (3) Cancel.

As you can see, each has similar but different methods.

Since we use multiple vendors, to fit in all the different interfaces, I've designed VendorPayment with Strategy Pattern: VendorService -> Vendor Strategy -> {vendor1, vendor2, vendor3}. Regardless of what each vendor has to offer in terms of its interface, now they all have the same interface through VendorService.

On the other hand, local payment is simple and plain. Just the local payment itself.

Now that we have 2 ways of making payment but with different interfaces on their own, I have following structure:

PaymentGatewayService -> VendorPayment
-> LocalPayment

I guess the simplest way to make this happen is to just use switch case. Below is psuedo-code.

class PaymentGatewayService {
  payment = PaymentInterface; 

  constructor() {
  }

  selectMethod(dto: PGDto) {
    if (PGDto.method === 'local') {
      return new LocalPayment();
    }

    if (PGDto.method === 'vendor') {
      return new VendorPayment('paypal');
    }
  }

  pay(dto: Dto) {
    this.payment.pay(dto) 
    ...
  }

  checkstatus(dto: Dto) {}

  fund(dto: Dto) {}

  cancel(dto: Dto) {} 
}

The problem with above code is obviously that it violates Open-Closed Principle since when we need to add method, it would have to touch existing logic. Additionally, since I plan on building sdk on top of this Service, I need to have outer interface that offers conditional methods (like based on what user types in, parameter requirement has to change). What would be the ideal way to approach this type of situation?

Aucun commentaire:

Enregistrer un commentaire