Different with using abstract class

there is a difference between using the Strategy pattern and having an abstract method that all child classes inherit from. The key distinction lies in how the algorithms or behaviors are encapsulated and how they are used or changed at runtime.

Abstract Method in Inheritance

When you use an abstract method in a base class that all child classes inherit and implement, you are defining a fixed set of behaviors that are tied to the specific classes. This approach is static and the behavior is determined at compile time.

Example

using System;

public abstract class Payment
{
    public abstract void Pay(decimal amount);
}

public class CreditCardPayment : Payment
{
    public override void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using Credit Card.");
    }
}

public class PayPalPayment : Payment
{
    public override void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using PayPal.");
    }
}

public class CryptoPayment : Payment
{
    public override void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using Cryptocurrency.");
    }
}

class Program
{
    static void Main()
    {
        Payment payment;

        // Pay using Credit Card
        payment = new CreditCardPayment();
        payment.Pay(120.00m);

        // Pay using PayPal
        payment = new PayPalPayment();
        payment.Pay(75.50m);

        // Pay using Cryptocurrency
        payment = new CryptoPayment();
        payment.Pay(250.00m);
    }
}

Strategy Pattern

The Strategy pattern encapsulates each algorithm (or behavior) in a separate class and makes them interchangeable. The main benefit is that you can change the algorithm used by the context object at runtime.

Example

using System;

// Strategy Interface
public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

// Concrete Strategies
public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using Credit Card.");
    }
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using PayPal.");
    }
}

public class CryptoPayment : IPaymentStrategy
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paying {amount:C} using Cryptocurrency.");
    }
}

// Context
public class PaymentContext
{
    private IPaymentStrategy paymentStrategy;

    public void SetPaymentStrategy(IPaymentStrategy strategy)
    {
        this.paymentStrategy = strategy;
    }

    public void ProcessPayment(decimal amount)
    {
        if (paymentStrategy == null)
        {
            throw new InvalidOperationException("Payment strategy is not set.");
        }

        paymentStrategy.Pay(amount);
    }
}

// Program
class Program
{
    static void Main()
    {
        PaymentContext paymentContext = new PaymentContext();

        // Pay using Credit Card
        paymentContext.SetPaymentStrategy(new CreditCardPayment());
        paymentContext.ProcessPayment(120.00m);

        // Pay using PayPal
        paymentContext.SetPaymentStrategy(new PayPalPayment());
        paymentContext.ProcessPayment(75.50m);

        // Pay using Cryptocurrency
        paymentContext.SetPaymentStrategy(new CryptoPayment());
        paymentContext.ProcessPayment(250.00m);
    }
}

Differences

  1. Flexibility at Runtime:

    • Abstract Method: The behavior is defined at compile time and cannot be changed dynamically.

    • Strategy Pattern: The behavior can be changed at runtime by setting a different strategy.

  2. Encapsulation:

    • Abstract Method: The behavior is encapsulated in the derived classes, which are tied to a specific type hierarchy.

    • Strategy Pattern: The behavior is encapsulated in separate strategy classes, promoting composition over inheritance.

  3. Open/Closed Principle:

    • Abstract Method: Adding new behaviors requires modifying the class hierarchy, potentially violating the open/closed principle.

    • Strategy Pattern: New behaviors can be added by creating new strategy classes without modifying existing ones, adhering to the open/closed principle.

  4. Reusability:

    • Abstract Method: Behaviors are tied to the specific class hierarchy and may not be easily reusable outside of it.

    • Strategy Pattern: Behaviors are encapsulated in independent strategy classes that can be reused by different contexts.

Last updated