Join our WhatsApp Channel
Cart / 0.00$

No products in the cart.

Visit Support Portal
No Result
View All Result
Thursday, November 5, 2026
  • Home
  • Tutorials
    • Machine Learning
    • Python
    • Web Development
    • Javascript
    • Mathematics
    • Deep Learning
    • Artificial Intelligence
  • Store
  • Our ServicesBook Now
    • Managed Hosting Services
    • Web Development Services
    • Digital Marketing Services
    • Website Security Checker
    • Video Editing Services
  • Our Softwares
    • JaggoRe AIFree
    • Email ExtractorPaid
    • TimeWell AppFree
Get a Free Quote
  • Login
  • Register
Neuraldemy
Thursday, November 5, 2026
Cart / 0.00$

No products in the cart.

No Result
View All Result
Neuraldemy
Get A Free Quote
Home Javascript

Strategy Pattern In JavaScript/TypeScript

Neuraldemy by Neuraldemy
March 3, 2026 - Updated on October 23, 2026
in Javascript, NodeJS, System Design, Web Development
Reading Time: 23 mins read
A A
Strategy Pattern In JavaScript/TypeScript

In the previous tutorial, we learnt about factory pattern, in this tutorial we will learn about strategy pattern in JavaScript. Imagine you are designing the checkout system of an e-commerce application. Customers can pay using a credit card, PayPal, or cryptocurrency. Each payment method follows a different process, but the checkout workflow should remain largely the same.

The application must accept an order, initiate payment, and continue the checkout process. What should vary is the logic used to process the payment.

A straightforward implementation might place every payment method inside the checkout class:

class CheckoutProcessor {
  processOrder(amount: number, paymentType: string): void {
    if (paymentType === "CARD") {
      // Process credit card payment
    } else if (paymentType === "PAYPAL") {
      // Process PayPal payment
    } else if (paymentType === "CRYPTO") {
      // Process cryptocurrency payment
    }
  }
}

This can work for a small application, but the checkout processor now knows how every payment method works. Adding a new provider requires modifying the same class that coordinates checkout.

More importantly, the different payment algorithms are embedded inside the workflow that uses them.

The underlying design problem is this: how can we change the behavior used by an object without repeatedly modifying the object’s core logic?

The Strategy Pattern provides an answer by separating a family of algorithms into interchangeable objects.

Instead of making the checkout processor responsible for every payment implementation, we give it a payment strategy and let that strategy perform the payment-specific behavior.

2. The Core Idea Behind the Strategy Pattern

The Strategy Pattern is a behavioral design pattern. Its purpose is to define a family of algorithms, encapsulate each one behind a common interface, and make them interchangeable.

In our payment example, credit card, PayPal, and cryptocurrency payments are different strategies for performing the same high-level operation: paying an amount.

The design has three main participants.

Strategy: A common interface that defines the operation every payment strategy must support.

Concrete strategies: Implementations of that interface, each containing a different payment algorithm or provider integration.

Context: The object that uses a strategy to perform its work. In our example, CheckoutProcessor is the context.

The relationship looks like this:

            CheckoutProcessor                 (Context)
                    |
                    | delegates payment to
                    v
             IPaymentStrategy
                (Interface)
                    ^
           __________|__________
          |          |          |
          |          |          |
          v          v          v
      CreditCard   PayPal     Crypto
      Payment      Payment    Payment
      Strategy     Strategy   Strategy

The context knows how to use the strategy, but it does not need to know the internal algorithm implemented by each concrete strategy.

This changes the design from choosing behavior through conditions scattered across the application to choosing an object that already encapsulates the required behavior.

The strategy can be selected when the context is created or changed later, depending on the application’s requirements.

3. Define the Strategy Interface

We begin by defining the common contract:

interface IPaymentStrategy {
  pay(amount: number): void;
}

Every payment strategy must implement pay().

The interface does not specify how payment should work. It only establishes the operation that the checkout processor can rely on.

A credit card provider may require a payment token and a gateway request. PayPal may use a separate SDK, while a cryptocurrency implementation may interact with a wallet or payment service.

Those implementation details belong inside their respective strategies.

The shared interface creates a boundary between the caller and the concrete algorithms.

This is important because the context can now depend on IPaymentStrategy rather than directly depending on CreditCardPayment, PayPalPayment, or CryptoPayment.

That is the core abstraction on which the pattern relies.

4. Implement the Concrete Strategies

Each concrete strategy implements the same interface but provides its own behavior.

Credit Card Payment

class CreditCardPayment implements IPaymentStrategy {
  private cardNumber: string;

  constructor(cardNumber: string) {
    this.cardNumber = cardNumber;
  }

  public pay(amount: number): void {
    console.log(
      `Processing $${amount} via Credit Card ending in ${this.cardNumber.slice(-4)}`,
    );
  }
}

The class stores the information it needs and implements the pay() operation.

Its constructor receives a card number, and the implementation displays only the final four digits in its message.

The important design detail is that card-specific state and behavior live together inside CreditCardPayment. The checkout processor does not need to understand how this strategy uses its card information.

This example is intended to demonstrate the pattern. Production payment systems should use a payment provider’s SDK and tokenized payment details rather than storing or handling raw card numbers unnecessarily.

PayPal Payment

class PayPalPayment implements IPaymentStrategy {
  private emailAddress: string;

  constructor(emailAddress: string) {
    this.emailAddress = emailAddress;
  }

  public pay(amount: number): void {
    console.log(
      `Processing $${amount} via PayPal account: ${this.emailAddress}`,
    );
  }
}

PayPal uses an email address in this simplified implementation. Its algorithm differs from the credit card implementation, but its public contract remains the same.

The checkout processor does not need to know that this class stores an email address. It only needs an object whose pay() method accepts the amount.

Cryptocurrency Payment

class CryptoPayment implements IPaymentStrategy {
  private walletAddress: string;

  constructor(walletAddress: string) {
    this.walletAddress = walletAddress;
  }

  public pay(amount: number): void {
    console.log(
      `Processing $${amount} via Crypto Wallet: ${this.walletAddress}`,
    );
  }
}

The cryptocurrency strategy uses a wallet address rather than card details or a PayPal account.

We now have three independent implementations of the same contract. They can evolve separately without forcing the checkout processor to absorb their internal logic.

In a real application, each method would connect to the appropriate payment integration and handle its specific response, errors, authentication, and transaction state.

5. Build the Context: CheckoutProcessor

The context is the component that uses the selected strategy.

class CheckoutProcessor {
  private paymentStrategy: IPaymentStrategy;

  constructor(strategy: IPaymentStrategy) {
    this.paymentStrategy = strategy;
  }

  public setPaymentStrategy(strategy: IPaymentStrategy): void {
    this.paymentStrategy = strategy;
    console.log("--> Payment strategy updated.");
  }

  public processOrder(amount: number): void {
    console.log("Starting checkout process...");
    this.paymentStrategy.pay(amount);
    console.log("Checkout complete!\n");
  }
}

There are three important design decisions here.

The Context Stores an Interface, Not a Concrete Class

private paymentStrategy: IPaymentStrategy;

The context can hold any object that implements IPaymentStrategy.

It does not declare its field as CreditCardPayment or PayPalPayment. That means its implementation does not need to change just because another payment strategy is introduced.

This is an example of programming to an abstraction rather than coupling the context to one concrete implementation.

The Strategy Is Injected Through the Constructor

constructor(strategy: IPaymentStrategy) {
  this.paymentStrategy = strategy;
}

The context does not create the strategy itself. Whoever constructs CheckoutProcessor supplies the strategy it should use.

This is a form of dependency injection: an object receives a dependency from outside instead of constructing that dependency internally.

It allows the calling code to decide which behavior the checkout processor should use, while the processor remains focused on coordinating checkout.

The Context Delegates the Payment Operation

this.paymentStrategy.pay(amount);

This is the essential line.

CheckoutProcessor does not calculate how to authorize a credit card, initiate a PayPal transaction, or submit a cryptocurrency payment. It delegates that operation to whichever strategy it currently holds.

Because the strategies implement the same interface, the context can make the same method call regardless of which implementation is being used.

This is polymorphism working together with composition.

6. Execute the Example: Switching Strategies at Runtime

Let’s put the components together.

const creditCardMethod =
  new CreditCardPayment("4111222233334444");

const checkout = new CheckoutProcessor(creditCardMethod);

checkout.processOrder(150.0);

const paypalMethod =
  new PayPalPayment("user@example.com");

checkout.setPaymentStrategy(paypalMethod);

checkout.processOrder(45.5);

Expected output:

Starting checkout process...
Processing $150 via Credit Card ending in 4444
Checkout complete!

--> Payment strategy updated.
Starting checkout process...
Processing $45.5 via PayPal account: user@example.com
Checkout complete!

Let’s follow what happens.

First, the application creates a CreditCardPayment object and passes it into CheckoutProcessor. The context stores a reference to this object.

When processOrder(150.0) runs, the context delegates the payment operation to its current strategy. The credit card implementation handles the call.

Next, the application creates a PayPalPayment object and passes it to setPaymentStrategy(). The context replaces its strategy reference.

The next call to processOrder(45.5) therefore invokes PayPalPayment.pay() instead of CreditCardPayment.pay().

Notice that processOrder() did not need to be rewritten. The behavior changed because the object it delegates to changed.

That is the central benefit of the Strategy Pattern: the context can vary its behavior by changing the strategy it uses, rather than by adding more conditional logic to its own implementation.

The example can also use the cryptocurrency strategy in exactly the same way:

const cryptoMethod =
  new CryptoPayment("wallet_abc123");

checkout.setPaymentStrategy(cryptoMethod);
checkout.processOrder(80);

The checkout processor does not require a new crypto-specific method or branch.

7. Why This Design Is Better Than a Large Conditional

The Strategy Pattern is not valuable merely because it removes an if statement. Its real value comes from separating behavior that varies from the workflow that stays stable.

In the original conditional implementation, the checkout processor needed to know which concrete class to construct and how to select it. As payment methods grew, that knowledge accumulated inside one class.

With strategies, each payment implementation owns its own behavior. The context depends on the interface, and the application can choose the implementation independently.

This supports a design principle often summarized as: encapsulate what varies.

It also follows the Open/Closed Principle to a useful extent. You can introduce a new class that implements IPaymentStrategy without changing the context’s payment delegation logic.

There is a qualification, though. If the application still uses a conditional elsewhere to select the strategy, that selection logic may also need to change when a new payment type is added. Strategy separates the algorithms; it does not automatically solve strategy discovery or configuration.

For a small application, an explicit selection at the application boundary is often enough. More elaborate registration or provider-selection mechanisms can be introduced when the requirements justify them.

8. When Is the Strategy Pattern Useful?

The pattern is useful when an application supports several interchangeable ways to perform the same conceptual operation.

Payment processing is one example. An order may use a different payment provider without the order workflow needing to understand each provider’s implementation.

Shipping calculations are another. A logistics application could have separate strategies for standard shipping, express shipping, and international shipping. The checkout system would pass the shipment information to the selected strategy without embedding every pricing formula into the order service.

Discount calculation is also a natural fit. A shopping platform could apply seasonal discounts, membership discounts, or promotional pricing using different algorithms behind a common calculateDiscount() interface.

Other examples include authentication mechanisms, compression algorithms, route-planning algorithms, file export formats, and retry policies.

In each case, ask whether the application has one stable operation but multiple interchangeable implementations. If it does, the Strategy Pattern may provide a useful boundary.

9. Engineering Trade-offs and Production Considerations

The Strategy Pattern introduces additional objects and interfaces. For a single trivial operation with no realistic variation, that structure may be unnecessary. A simple function or conditional may be easier to maintain.

The pattern is most valuable when the algorithms have meaningful differences, are expected to evolve independently, or need to be selected at runtime.

It also shifts the responsibility of choosing a strategy to another part of the application. That is intentional, but the selection mechanism still needs to be designed. The application must determine which strategy is appropriate for a particular order and ensure it is properly configured.

Our sample method also returns void, so the context cannot tell whether a payment succeeded or failed. It prints "Checkout complete!" after invoking the strategy regardless of the real-world outcome. That is acceptable for demonstrating delegation, but it is not enough for real payment processing.

A production-oriented interface might look like this:

interface IPaymentStrategy {
  pay(amount: number): Promise<PaymentResult>;
}

Here, PaymentResult would represent the application’s defined success or failure result. The context could await the operation and complete the order only after the payment workflow reports the appropriate outcome.

The important distinction is that the Strategy Pattern determines how interchangeable behavior is organized. It does not, by itself, provide transaction safety, retries, idempotency, payment security, or error handling. Those concerns must be addressed by the broader payment design.

Conclusion

The Strategy Pattern solves a design problem that appears whenever a system needs several interchangeable implementations of the same operation.

In our example, IPaymentStrategy defines the contract, each payment class encapsulates one implementation, and CheckoutProcessor acts as the context that delegates payment to the currently selected strategy. Constructor injection establishes the initial behavior, while setPaymentStrategy() allows that behavior to change at runtime.

The design separates the checkout workflow from the details of payment execution. It reduces the context’s dependency on concrete classes and allows new strategies to be introduced without rewriting the delegation logic.

When applying the pattern in low-level design, focus on the underlying question: does this class contain behavior that varies independently from the workflow that uses it? When the answer is yes, extracting that behavior into interchangeable strategies can make the system easier to extend, test, and reason about.

Support

Buy author a coffee

Support
SummarizeSendShareTweetScan
Previous Post

Factory Pattern In JavaScript/TypeScript

Next Post

FormData API: A Beginner’s Guide to Native Validation

Neuraldemy

Neuraldemy

This is Neuraldemy support. Subscribe to our YouTube channel for more.

Related Posts

The Node.js Process Object and Environment Configuration Explained

Node.js EventEmitter Explained: Events, Listeners, and Event-Driven Architecture

DNS And TCP in Node.js Explained

HTTPS and TLS in Node.js Explained : Encryption, Certificates, Handshakes, and Secure Servers

HTTP Explained: History, Protocol Internals, and Building a Web Server with Node.js

Node.js Streams Explained: Readable, Writable, Transform, and Backpressure

Next Post
FormData API: A Beginner’s Guide to Native Validation

FormData API: A Beginner’s Guide to Native Validation

100 CSS Interview Questions

100 CSS Interview Questions

Why RAM Prices Will Continue To Rise?

Support

Buy author a coffee

Support

Support Neuraldemy

Newsletter

Top rated products

  • Probability and Statistics for Machine Learning and Data Science Probability and Statistics for Machine Learning and Data Science
    Rated 5.00 out of 5
    30.00$ Original price was: 30.00$.12.99$Current price is: 12.99$.
  • SVM Notes: Optimization & Implementation SVM Notes: Optimization & Implementation
    Rated 5.00 out of 5
    9.99$ Original price was: 9.99$.4.99$Current price is: 4.99$.
  • spidy mail hunter software Spidy Mail Hunter: Powerful And Intelligent Website & PDF Email Extractor Software (Windows App)
    Rated 4.78 out of 5
    149.00$ Original price was: 149.00$.49.00$Current price is: 49.00$.
  • Linear Algebra For Machine Learning And Data Science Linear Algebra For Machine Learning And Data Science
    Rated 4.71 out of 5
    40.00$ Original price was: 40.00$.20.99$Current price is: 20.99$.
  • Starter Website Package Infographic Starter Business & Creator Website Package (3 Pages + 1 Year Free Hosting) 199.00$ Original price was: 199.00$.149.00$Current price is: 149.00$.

Recent Posts

The Node.js Process Object and Environment Configuration Explained

Node.js EventEmitter Explained: Events, Listeners, and Event-Driven Architecture

DNS And TCP in Node.js Explained

November 2026
M T W T F S S
 1
2345678
9101112131415
16171819202122
23242526272829
30  
« Oct    

Neuraldemy

Neuraldemy

Neuraldemy

Software Development

Neuraldemy helps you learn ML, AI, Web Dev and data science from scratch. Addtionally, we also provide web development and hosting services for businesses, and individuals

[convertkit form=7049059]
  • Get Started
  • Contact
  • Book Services
  • Privacy Policy
  • Terms Of Use
  • Support Portal
  • Managed Hosting Terms
  • Web Development Terms
  • Refund Policy
Neuraldemy

© 2026 - A learning platform by Odist Magazine

Welcome Back!

Login to your account below

Forgotten Password? Sign Up

Create New Account!

Fill the forms below to register

*By registering into our website, you agree to the Terms & Conditions and Privacy Policy.
All fields are required. Log In

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
Join Our WhatsApp Channel
  • Home
  • Tutorials
    • Machine Learning
    • Python
    • Web Development
    • Javascript
    • Mathematics
    • Deep Learning
    • Artificial Intelligence
  • Store
  • Our Services
    • Managed Hosting Services
    • Web Development Services
    • Digital Marketing Services
    • Website Security Checker
    • Video Editing Services
  • Our Softwares
    • JaggoRe AI
    • Email Extractor
    • TimeWell App
  • Login
  • Sign Up
  • Cart
Order Details

© 2026 - A learning platform by Odist Magazine

This website uses cookies. By continuing to use this website you are giving consent to cookies being used.
0