Strategy Design Pattern in Go

1. Definition

The Strategy Design Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

2. Problem Statement

Imagine you have a system that requires multiple ways to execute a particular action (e.g., sorting). Hardcoding each algorithm or using complex conditional logic can make the system rigid, less maintainable, and harder to extend.

3. Solution

Encapsulate each algorithm (or strategy) into separate classes with a common interface. This will allow you to switch algorithms or strategies on-the-fly without altering the code that uses them.

4. Real-World Use Cases

1. Different methods for calculating shipping costs.

2. Various strategies for compressing files.

3. Different AI behaviors in a game.

5. Implementation Steps

1. Define a strategy interface that describes how the strategies will be invoked.

2. Implement multiple concrete strategy classes based on the strategy interface.

3. Context class which uses a strategy should have a method to set the strategy, and then it can delegate the algorithmic work to the strategy object.

6. Implementation in Go

// Strategy interface
type SortingStrategy interface {
	Sort(dataset []int) []int
}
// Concrete strategy 1: Bubble Sort
type BubbleSort struct {}
func (b *BubbleSort) Sort(dataset []int) []int {
	// ... bubble sort algorithm ...
	return dataset  // just for the sake of simplicity
}
// Concrete strategy 2: Quick Sort
type QuickSort struct {}
func (q *QuickSort) Sort(dataset []int) []int {
	// ... quick sort algorithm ...
	return dataset  // again, simplified
}
// Context class
type Sorter struct {
	strategy SortingStrategy
}
func (s *Sorter) SetStrategy(strategy SortingStrategy) {
	s.strategy = strategy
}
func (s *Sorter) ExecuteStrategy(dataset []int) []int {
	return s.strategy.Sort(dataset)
}
// Client code
func main() {
	data := []int{5, 3, 4, 1, 2}
	sorter := &Sorter{}
	// Use Bubble Sort
	sorter.SetStrategy(&BubbleSort{})
	sortedData := sorter.ExecuteStrategy(data)
	fmt.Println("Bubble Sort:", sortedData)
	// Switch to Quick Sort
	sorter.SetStrategy(&QuickSort{})
	sortedData = sorter.ExecuteStrategy(data)
	fmt.Println("Quick Sort:", sortedData)
}

Output:

Bubble Sort: [5, 3, 4, 1, 2]
Quick Sort: [5, 3, 4, 1, 2]
(Note: The output displays unsorted data for simplicity. In a real-world application, the data would be sorted.)

Explanation:

1. The SortingStrategy interface defines a Sort method, which all concrete strategies must implement.

2. BubbleSort and QuickSort are concrete strategies that implement the SortingStrategy.

3. The Sorter context class allows you to set a strategy and then execute it.

4. In the client code, we set different strategies and execute them.

7. When to use?

Use the Strategy pattern when:

1. You want to define a class that can have one of a number of behaviors.

2. You need to switch algorithms or strategies at runtime.

3. You have a lot of conditional statements that choose different variations of an algorithm.


Comments