0

I have the following code

class Store { 
    constructor(paymentProcessor) {
        this.paymentProcessor = paymentProcessor;
    }
   
    purchaseBike(price, quantity) {
        if(this.paymentProcessor instanceof StripePaymentProcessor) {
            this.paymentProcessor.pay(price * quantity); 
        } else {
            let token = generateToken();
            this.paymentProcessor.pay(price * quantity, token, new Date()); 
        }
    }

    purchaseHelmet(price, quantity) {
        if(this.paymentProcessor instanceof StripePaymentProcessor) {
            this.paymentProcessor.pay(price * quantity); 
        } else {
            let token = generateToken();
            this.paymentProcessor.pay(price * quantity, token, new Date()); 
        }
    }

}

function generateToken() {
    return 'sdsd1212zwsd';
}


class StripePaymentProcessor {
    constructor(user) {
        this.stripe = new Stripe(user);
    }

    pay(amountInDollars) {
        this.stripe.makePayment(amountInDollars * 100);
    }
}

class PaypalPaymentProcessor {
    constructor(user) {
        this.paypal = new Paypal();
        this.user = user;
    }

    pay(amountInDollars, token, date) {
        this.paypal.makePaypalPayment(this.user,amountInDollars, token, date);
    }
}

class Stripe {
    constructor(user) {
        this.user = user;
    }

    makePayment(amountInCents) {
        console.log(`${this.user} made payment of $${amountInCents / 100} with Stripe`)
    }
}


class Paypal {
    makePaypalPayment(user, amountInDollars, token, date) {
        console.log(`${user} made payment of $${amountInDollars} with Paypal on the following date ${date}`)
    }
}

const store = new Store(new StripePaymentProcessor('Andrej'));
store.purchaseBike(200,2);
store.purchaseHelmet(200,2);


// const store = new Store(new PaypalPaymentProcessor('Andrej'));
// // 200 dollars is one bike - and we want 2 bikes
// store.purchaseBike(200, 2);
// store.purchaseHelmet(15,2);

the idea for this code is from this youtube video where i tried to extend the code with more dificcult scenario where the methods from the processors will not have same name and will expect different number of arguments https://www.youtube.com/watch?v=9oHY5TllWaU&t=614s

So we introduce here Processors for some payments, so our code will not be hardcoding the use of paypal or stripe api methods.

So when i can my 'paymethod, in background it knows if it needs to call thepay` method API from Stripe or from Paypal.

And that works great.My problem is when i need to call my internal pay method. There for Stripe it is expecting only one argument,

and for Paypal it is expecting three arguments.

price * quantity, token, new Date().

We are sending just the token simulating authorization things that will happen on the Stripe side.

As you can see i am resolving this with if else statements where i check if it is instance of StripePaymentProcessor otherwise else statement is called.

Problem with this approach is that in future if we add another paypantpreprocessor with different method arguments, i need to add another if statement. Also there are no just makePayment methods from the payment providers, there are a lot of other methods and i can't hardcode with if else statements every one of them.

How can this be solved ?

A_A
  • 1,832
  • 2
  • 11
  • 17
JohnJS
  • 35
  • 3
  • You want to make your code DRY, but every payment method behaves differently, not a good idea to make one function to rule them all. – Joseph Aug 10 '22 at 09:51
  • @JosephWang thank you for your answer. But with this approach I am breaking the open/closed principle where for every another feature i need to modify the code base, and i am not adding the new feature from outside, in future it will be big pain with this if else statements for every payment provider – JohnJS Aug 10 '22 at 09:53
  • `purchaseBike` `purchaseHelmet` both invoke payments, that's why you think it's a big pain, you need to standarize your shop items instead of various different payments. You should only pass final total price amount to your payment object. – Joseph Aug 10 '22 at 10:03
  • Instead of `purchaseBike` `purchaseHelmet`, why not `purchase([{product: 'bike'}, {product: 'helmet'}])`, then you can have only one purchse to organize all you payments method. – Joseph Aug 10 '22 at 10:04
  • You are right, but still inside purchase i will need to have if else statemens where depending on the provider i need to send different arguments to the real API method – JohnJS Aug 10 '22 at 10:06
  • Yeah, but some payment methods might redirect you to another page, some might request a phone sms OTP, some can charge one dollar to validate card, it's too many, how can you standarize all these things? – Joseph Aug 10 '22 at 10:08

0 Answers0