Ember Handbook

Strategy Pattern

Intent

The strategy pattern is a family of algorithms, each one encapsualted and by that interchangeable to the receivers (Gamma, Helm, Johnson & Vlissides, 1994, p. 315; Shvets, n.d.).

Structure

The strategy interface defining the algorithms, a context calling the algorithms of that interface implemented by a concrete strategy.

Object Oriented Way

A Client instantiates a ConcreteStrategy and passes it to the Context. The Context is receving any Strategy that fulfills the interface.

class Client {
  run() {
    const strategy = new ConcreteStrategy();
    const ctx = new Context();
    ctx.strategy = strategy;
  }
}

Declarative Way

It’s similar on a pure declarative way, where an interface describes the arguments to take on a component level. The client invokes a component and passes in another component (the ConcreteStrategy) to fulfill the contract of arguments. To demonstrate this, typescript helps a lot:

The ToggleLabelComponent is the default concrete strategy, implements and provies the ToggleLabelArgs strategy interface. The FancyLabelComponent implements the same interface for the args and by that, makes the default label interchangeable. Here is how to invoke it:

<Toggle @labelComponent={{component "fancy-label"}} />

For components we usually provide a decent default, that’s why this component can be used without a @labelComponent passed in but provides this option. More on this example can be found in the composable component type.

Combination of Both Ways

Combining the object oriented and declarative way can extend the usefulness of this pattern. Instead of passing in a component as another strategy, swapping in a javascript object containing algorithms for business logic. This way, UI and business logic/flows can be separated and be interchangeable.

Applicability