One idea
Use Strategy when one part of your code chooses between multiple ways to do the same job.
The caller should not know the details. It should ask a strategy to do the work.
Where it appears
You see Strategy-shaped pain when a method has many branches based on type, mode, provider, plan, or payment method.
Common examples: UPI vs card vs COD payments, percentage vs flat discounts, CSV vs PDF exports, or different scoring rules in a quiz app.
Do not pattern everything
Do not create Strategy for two tiny if statements that never change. That adds files without removing real pain.
Use it when behavior changes often, branches are growing, or each branch has different rules and tests.
Before refactor
This checkout code works, but every new payment method edits the same function. That makes merge conflicts likely during a hackathon.
It also mixes checkout flow with payment rules.
// checkout.js
function pay(order, method) {
if (method === "upi") {
console.log(`Collect ₹${order.total} using UPI for ${order.customerVpa}`);
return { status: "paid", provider: "upi" };
}
if (method === "card") {
console.log(`Charge ₹${order.total} to card ending ${order.cardLast4}`);
return { status: "paid", provider: "card" };
}
if (method === "cod") {
console.log(`Mark ₹${order.total} as cash on delivery`);
return { status: "pending", provider: "cod" };
}
throw new Error("Unknown payment method");
}After refactor
Now each payment method is a strategy. The checkout flow only calls pay.
Adding wallet payment means adding one new strategy and registering it. You do not edit checkout.
// paymentStrategies.js
const paymentStrategies = {
upi: {
pay(order) {
console.log(`Collect ₹${order.total} using UPI for ${order.customerVpa}`);
return { status: "paid", provider: "upi" };
}
},
card: {
pay(order) {
console.log(`Charge ₹${order.total} to card ending ${order.cardLast4}`);
return { status: "paid", provider: "card" };
}
},
cod: {
pay(order) {
console.log(`Mark ₹${order.total} as cash on delivery`);
return { status: "pending", provider: "cod" };
}
}
};
function getPaymentStrategy(method) {
const strategy = paymentStrategies[method];
if (!strategy) throw new Error("Unknown payment method");
return strategy;
}
module.exports = { getPaymentStrategy };
// checkout.js
const { getPaymentStrategy } = require("./paymentStrategies");
function pay(order, method) {
const strategy = getPaymentStrategy(method);
return strategy.pay(order);
}
module.exports = { pay };How to refactor
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Use AI well
Ask AI to identify the repeated action and suggest Strategy names. Then check that every strategy has the same method signature and return shape.
Do not accept a huge class hierarchy blindly. In JavaScript or Python, plain objects and functions are often enough.
Prompt:
I have this function with if/else branches. Refactor it using the Strategy pattern. Keep it simple. Use the same input and output shape. Explain what changed and what tests I should run.Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done