How Factory and Strategy Patterns Work Together
Understanding the Synergy Between Factory and Strategy Design Patterns in C#
In software development, writing flexible and maintainable code is key. Two of the most useful design patterns for achieving this are the Factory and Strategy patterns. While they address different challenges, combining them can make your system highly extensible and robust.
In this post, we’ll explore how to implement a payment system with dynamic behaviors like discounts to see how these patterns work together in a real-world scenario.
What is the Factory Pattern?
The Factory Pattern is a creational design pattern. Its purpose is to decouple the client from the creation of objects.
Imagine a payment system where a user can choose Credit Card, PayPal, or bKash.
The client shouldn’t worry about which class is instantiated.
The Factory decides which payment object to create.
This separation makes the system easy to extend with new payment methods without changing the client code.
What is the Strategy Pattern?
The Strategy Pattern is a behavioral design pattern. It allows changing the behavior of an object dynamically at runtime.
In our payment system, different customers may have different discount rules:
Regular customer → no discount
Premium customer → 10% discount
Festival offer → 20% discount
Corporate deal → custom discount
With the Strategy Pattern, these rules can change without modifying the payment class.
How Factory and Strategy Work Together
By combining these patterns:
Factory creates the appropriate payment type (Credit Card, PayPal, bKash).
Strategy applies the correct discount dynamically based on customer type or promotion.
This combination allows you to:
Add new payment methods easily
Introduce new discount strategies without touching existing code
Sample Code Implementation in C
Step 1: Define Discount Strategies
public interface IDiscountStrategy
{
decimal ApplyDiscount(decimal amount);
}
public class RegularCustomerDiscount : IDiscountStrategy
{
public decimal ApplyDiscount(decimal amount) => amount;
}
public class PremiumCustomerDiscount : IDiscountStrategy
{
public decimal ApplyDiscount(decimal amount) => amount * 0.90m;
}
public class FestivalDiscount : IDiscountStrategy
{
public decimal ApplyDiscount(decimal amount) => amount * 0.80m;
}
public class CorporateDealDiscount : IDiscountStrategy
{
private readonly decimal _discountPercentage;
public CorporateDealDiscount(decimal discountPercentage)
{
_discountPercentage = discountPercentage;
}
public decimal ApplyDiscount(decimal amount) =>
amount - (amount * _discountPercentage / 100);
}
Step 2: Define Payment Interface and Classes
public interface IPayment
{
void SetDiscountStrategy(IDiscountStrategy discountStrategy);
void ProcessPayment(decimal amount);
}
public class CreditCardPayment : IPayment
{
private IDiscountStrategy _discountStrategy = new RegularCustomerDiscount();
public void SetDiscountStrategy(IDiscountStrategy discountStrategy)
{
_discountStrategy = discountStrategy;
}
public void ProcessPayment(decimal amount)
{
var finalAmount = _discountStrategy.ApplyDiscount(amount);
Console.WriteLine($"Paid {finalAmount:C} using Credit Card.");
}
}
public class PayPalPayment : IPayment
{
private IDiscountStrategy _discountStrategy = new RegularCustomerDiscount();
public void SetDiscountStrategy(IDiscountStrategy discountStrategy)
{
_discountStrategy = discountStrategy;
}
public void ProcessPayment(decimal amount)
{
var finalAmount = _discountStrategy.ApplyDiscount(amount);
Console.WriteLine($"Paid {finalAmount:C} using PayPal.");
}
}
public class BkashPayment : IPayment
{
private IDiscountStrategy _discountStrategy = new RegularCustomerDiscount();
public void SetDiscountStrategy(IDiscountStrategy discountStrategy)
{
_discountStrategy = discountStrategy;
}
public void ProcessPayment(decimal amount)
{
var finalAmount = _discountStrategy.ApplyDiscount(amount);
Console.WriteLine($"Paid {finalAmount:C} using bKash.");
}
}
Step 3: Create the Payment Factory
public static class PaymentFactory
{
public static IPayment CreatePayment(string paymentMethod)
{
return paymentMethod.ToLower() switch
{
"creditcard" => new CreditCardPayment(),
"paypal" => new PayPalPayment(),
"bkash" => new BkashPayment(),
_ => throw new NotSupportedException("Payment method not supported")
};
}
}
Step 4: Example Usage
// Regular customer paying with Credit Card
var creditCardPayment = PaymentFactory.CreatePayment("creditcard");
creditCardPayment.SetDiscountStrategy(new RegularCustomerDiscount());
creditCardPayment.ProcessPayment(100m);
// Premium customer paying with PayPal
var payPalPayment = PaymentFactory.CreatePayment("paypal");
payPalPayment.SetDiscountStrategy(new PremiumCustomerDiscount());
payPalPayment.ProcessPayment(100m);
// Corporate deal paying with Credit Card (custom 25%)
var corporatePayment = PaymentFactory.CreatePayment("creditcard");
corporatePayment.SetDiscountStrategy(new CorporateDealDiscount(25));
corporatePayment.ProcessPayment(100m);
Benefits of This Approach
Extensibility: Easily add new payment methods or discount strategies.
Maintainability: Each class has a single responsibility.
Flexibility: Change discount rules at runtime without touching payment logic.
By combining Factory and Strategy, your payment system becomes dynamic, clean, and future-proof.
Don’t Confuse Factory and Strategy
It’s easy to mix up Factory and Strategy because both involve objects, but they solve completely different problems.
The Factory Pattern is all about creating objects. It decides which class should be instantiated so the client doesn’t have to know. For example, in a payment system, the Factory chooses between
CreditCardPayment,PayPalPayment, orBkashPayment. The client just asks for a payment method, and the Factory delivers the correct object.The Strategy Pattern, on the other hand, is about changing behavior at runtime. Once you have a payment object, you might want to apply different discount rules—regular, premium, festival, or corporate. Strategy lets you swap the discount logic without modifying the payment class itself.
Think of it this way:
Factory = which tool you pick
Strategy = how you use the tool