ឥរិយាបថ កម្រិតស្មុគស្មាញ: ទាប

Strategy in Go

Encapsulate interchangeable algorithms behind one interface so callers can swap behavior without branching on concrete rules.

The Problem

Business rules such as pricing, tax, ranking, or retry policies often vary by context. If every caller uses conditionals to choose which algorithm to run, the policy logic spreads out and becomes harder to test or replace.

The Solution

Strategy hides each algorithm behind a shared interface. In Go, strategies are often tiny interfaces backed by small structs or even function adapters. The caller holds one strategy value and delegates the variable behavior through that contract.

Structure

Strategy Pattern
Step 1 of 5

The Strategy Interface

PricingStrategy is the single-method contract: Calculate(items []CartItem) Money. All three concrete strategies satisfy this interface identically — Checkout only ever sees this shape.

  • Strategy interface: PricingStrategy defines how cart totals are calculated.
  • Concrete strategies: Standard, member, and campaign pricing apply different rules.
  • Context: Checkout delegates the calculation to the selected strategy.
  • Client: Chooses the strategy based on runtime context.

Implementation

This example calculates a cart total through interchangeable pricing strategies. The checkout flow does not branch on membership or campaign rules once a strategy has been selected.

package main

type CartLine struct {
	Name      string
	Qty       int
	UnitPrice int
}

type PricingStrategy interface {
	Total(lines []CartLine) int
}

type Checkout struct {
	strategy PricingStrategy
}

func NewCheckout(strategy PricingStrategy) Checkout {
	return Checkout{strategy: strategy}
}

func (c Checkout) Total(lines []CartLine) int {
	return c.strategy.Total(lines)
}

Real-World Analogy

Think of a navigation app choosing between fastest, cheapest, or scenic route options. The trip is the same, but the routing strategy changes how the path is calculated.

Pros and Cons

ProsCons
Makes algorithms easy to swap without changing callers.Adds abstraction that is unnecessary when one algorithm is stable.
Shrinks large conditionals into interchangeable policy objects.The caller or composition layer still has to choose the right strategy.
Supports focused testing of each rule set.Too many tiny strategies can make the design feel fragmented.

Best Practices

  • Keep strategy interfaces very small so new policies stay cheap to implement.
  • Inject the strategy from the outside; avoid contexts that secretly choose their own policy.
  • Use ordinary functions when a full struct adds no value. In Go, function types can be perfectly good strategies.
  • Prefer Strategy when callers need to swap algorithms at runtime.
  • Do not create a strategy hierarchy for logic that rarely changes or has only one implementation.

When to Use

  • You have several interchangeable algorithms with the same input and output shape.
  • Callers should choose policy without long conditional branches.
  • Different environments or customer tiers need different rules.

When NOT to Use

  • The logic is stable and a simple helper function is enough.
  • There is only one algorithm and no realistic need to swap it.
  • The abstraction would add more indirection than flexibility.