Home > .NET, Extreme Programming, Software Development > Bringing Plausible Deniability to Development: the Strategy Pattern

Bringing Plausible Deniability to Development: the Strategy Pattern

July 30th 2009 | David Cooksey

Bringing Plausible Deniability to Development: the Strategy Pattern

If the template pattern is a benevolent dictator the strategy pattern is a politician concerned with plausible deniability: Don’t tell me the details, just do it. The strategy is defined solely in terms of its inputs and outputs.

Let’s say you are writing a program that cuts checks for employees. The code that handles the physical printing of the checks is complete, all that remains is determining how much to print on the check for each person. The company contains both salaried and hourly employees in addition to salesmen whose pay is based on commissions. Also, the company sends out holiday checks to all employees at various times of the year based on how the company performed recently.

You want to be flexible, so your payment generator is designed as a windows service that polls a PaymentRequest table periodically. It then examines the type of payment to determine how the amount should be calculated. The next step is to write and organize implementations of the different ways to calculate payments.

The design should be flexible enough that it makes adding new payment types as simple as possible, while also providing as much flexibility as possible with respect to implementation details. You don’t want to mandate that a particular step in calculation occur, because you don’t know what future payment types might require.

This is where the strategy pattern comes into play. You can use a simple interface that defines your payment strategy to streamline your code and cut down on the number of decision points. All you really need is a block of code that looks at the payment record and decides what strategy to use. The other code should be the same regardless of the payment type. Here is some pseudo code for what this would look like:

public interface IPaymentStrategy
  {
    double CalculateAmount(IPaymentRequest paymentRequest);
  }

public class PaymentGenerator
  {
    public void LookForPaymentRequests()
    {
      IPaymentRequest[] paymentRequests= GetNewPaymentRequests();
      foreach (IPaymentRequest paymentRequest in paymentRequests)
      {
        Process(paymentRequest);
      }
    }

    private void Process(IPaymentRequest request)
    {
      IPaymentStrategy strategy;
      switch (request.PaymentType)
      {
        case 1:
          strategy = new HourlyPayment();
          break;
        case 2:
          strategy = new SalariedPayment();
          break;
        case 3:
          strategy = new CommissionPayment();
          break;
        case 4:
          strategy = new HolidayPayment();
          break;
        default:
          strategy = new FlatPayment();
          break;
      }
      double amount = strategy.CalculateAmount(request);
      WriteCheck(amount);
    }
}

IPaymentStrategy defines a simple interface that accepts an IPaymentRequest and returns the amount calculated. The PaymentGenerator pulls in new payment requests from a table. It picks the appropriate payment calculation method based on the payment type Id and uses it to generate the correct payment amount.

If a new payment type is added, it requires no code restructuring other than the creation of a new class that inherits from IPaymentStrategy, a new case block, and a new row in the PaymentType table.

This code structure places no restrictions at all on the implementation details of the individual payment types. If a lot of code is shared among the payment types, inheritance, a common dependency, or any other method can be used to reduce or eliminate code duplication entirely at the discretion of the programmer.

This makes it easier to ignore the gritty details of payment calculation which a more strict pattern such as the Template Pattern would force you to consider.

Flexible

Maintainable

Plausibly Deniable

The Strategy Pattern.

David Cooksey is a Senior .NET Consultant at Thycotic Software, an agile software services and product development company based in Washington DC. Secret Server is our flagship password management software product.

  1. August 10, 2009 at 4:02 pm

    David, great article and practical explanation. I was wondering if another way to keep from having to edit the switch statement for each new payment type that could be added in the future if you could simply let the PaymentRequest encapsulate which strategy to instantiate? So the process payment code would simply be reduced to:

    private void Process(IPaymentRequest request)
    {
    IPaymentStrategy strategy = request.paymentStrategy;

    double amount = strategy.CalculateAmount(request);
    WriteCheck(amount);

    }

    or something similar?

    thanks again!

    Tyler Madison

  2. August 18, 2009 at 4:10 pm

    Tyler,

    Good point.

    You could certainly do that, though if the decision point remains in code you would just be moving the case statement to another location. Instead of determining the strategy within the Process function, the strategy would have to be created somewhere within the code that creates the PaymentRequest.

    Since we’re adding a new class, we have to specify somewhere, either in code or via configuration, the link between a particular request and its strategy.

    In this case we could create a mapping table that links a PaymentTypeId to a strategy class name, in which case we could just use the class name to create an instance of the strategy to use.

    That has the benefit of being more configuration-based, and as such it would let you change what strategy to use for each payment type on the fly.

    David Cooksey

  1. July 31, 2009 at 9:23 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: