Strategy is a behavioural design pattern that lets you define a family of algorithms, encapsulate each of them into a separate class, and make them interchangeable. It allows you to chose varying but related algorithms at runtime for a specific situation or context.

Applicability

  • You need different variants of an algorithm
  • Multiple related algorithms (strategies) that can be used interchangeably.
  • Dynamic algorithm selection at runtime
  • Avoid using complex conditional statements that determine which algorithm to use
  • An algorithm uses data that should be hidden from its clients

Approach

  1. Identify the context where you want different strategies, the context typically contains a behaviour that should vary.
  2. Create an abstract strategy that defines the method(s) that represent the algorithms to be used by the context. This allows algorithms to be interchangeable. (dynamic method dispatch will be used)
  3. Define a family of algorithms (strategies) that implement the strategy interface, encapsulate each algorithm with specific behaviour into a separate class
  4. Design the context class that contains a reference to the strategy interface. This class should have a setter method to allow changing the strategy at runtime and a method that uses the strategy.
  5. Design the client code, create an instance of the context class and initialise it with a concrete strategy of choice. The strategy can dynamically changed by calling the setter method of the context.

Components

  • Strategy
    • An interface common to all supported algorithms
    • Used by context to call the algorithm defined by concrete strategies
  • Concrete strategy
    • Implement the algorithms using the strategy interface
  • Context
    • Hold reference to a concrete strategy object
    • Have a setter to allow choosing the strategy at runtime
    • Invoke the corresponding strategy behaviour(s)
  • Client
    • Choose a strategy
    • Use context object for executing selected strategy

Example

In this sale system example, which this implemented with the strategy pattern; the client is purchasing an item giving its quantity, price and choice of strategy, the system then calculate the total price.

Identify strategy pattern components

Strategy: SalePricing
Concrete strategy: SalePricingNormal, SalePricingDiscount, SalePricingCashBack Context: SalePricingContext Client: Client

Strategy

The SalePricing interface defines the contract for a family of algorithms. It provides support for interchangeable algorithms and will later used by the context with dynamic method dispatch.

public interface SalePrincing {
	public double getTotal(int qty, double price);
}

Concrete strategy

The concrete strategies provides different implementations of SalePrcing interface. They encapsulate vary logics into separate classes.

public class SalePricingNormal implements SalePricing {
	public double getTotal(int qty, double price) {
		return qty * price;
	}
}
public class SalePricingDiscount implements SalePricing {
	private double discount = 0.95;
	
	public double getTotal(int qty, double price) {
		return qty * price * discount;
	}
}
public class SalePricingCashBack implements SalePricing {
	private double discount = 10.0;
	private double threshold = 50.0;
 
	public double getTotal(int qty, double price) {
		double total = qty * price;
		if (total >= threshold) return total-discount;
		else return total;
	}
}

Context

Context will hold a reference to a concrete strategy object that passed by the client, and call the execution method on the linked strategy using dynamic method dispatch. The context doesn’t know what type of strategy it works with or how the algorithm is executed since the details are encapsulated.

public class SalePricingContext {
	//reference to a concrete strategy object
	private SalePricing salePricing;
 
	//strategy object passed by the client at runtime
	//AKA stragegy setter (determine which concretion will be used later)
	public SalePricingContext(SalePricing salePricing) {
		this.salePricing = salePricing;
	}
	public double getTotal(int qty, double price) {
		//invoke method on the linked strategy with dynamic method dispatch
		return salePricing.getTotal(qty, price);
	}
}

Client

The client create a specific strategy object and pass it to the context, the client can switch between different strategies at runtime as strategies are interchangeable and under the common strategy interface.

Pulic class Client {
	public static void main(String arg[]){
		//create a specific strategy with upcasting
		SalePricing salePricing = new SalePricingDiscount();
		//pass the stragety to context
		SalePricingContext context = new SalePricingContext(salePricing);
		double total = context.getTotal(6, 4);
		System.out.println("Total money to pay: " + total);
	}
}

Back to super node: Behavioural Patterns

Design_PatternBehavioural_Design_PatternsSOFT2201Strategy_PatternDynamic_Method_Dispatch