DEV Community

Sota
Sota

Posted on • Edited on

Strategy Pattern

What is Strategy Pattern?

Strategy Pattern is behavioral pattern that defines a family of algorithms, encapsulates each one by putting them into a separate class, and makes them interchangeable.

A family of algorithms refers to a set of algorithms that do the same but differently. Sorting algorithms are good example since they do the same things, SORTING! But process is not the same such as merge sort, bubble sort, quick sort.

When to use it?

Use Strategy pattern when you have many possible variation of algorithms.

For example, for a set of data, there's many possible searching algorithms such as linear search, binary search, jump search. Using Strategy pattern let us to change strategy dynamically with help of composition (you'll see in UML), that is, you can change searching algorithm for the set of data at runtime.

A good indication for applicability of strategy pattern is if we find different algorithms/behaviors in our methods which are selected with conditional statements like if-else or switch-case.

Problem

Assume we're developing card game system. it has two kinds of cards, hero and weapon. We can attach/detach a weapon card to hero card during a match, then the hero can use attached weapon.

Image description

The point is, useWeapon() in Hero class. Its implementation can be like this...

public void useWeapon(String attachedWeapon) {
        switch (attachedWeapon) {
            case "axe":
                // deal with axe weapon card
            case "sword":
                // deal with sword weapon card
            case "knife":
                // deal with knife weapon card
            default:
                // deal with no weapon card
        }
    }
Enter fullscreen mode Exit fullscreen mode

For now this is fine, but what if the game introduces 100 new weapon cards, we need to visit Hero class and modify switch block. Then, it will be more difficult to locate which part of our code causes a problem because now we have more than 100 cases in switch block. Even if we spot a bug and modify the code, it might create another issue in already-working code.

Solution

Image description

  1. Hero
    Maintains reference to WeaponStrategy object. setWeapon method allows client to dynamically change hero's behavior at runtime. Hero class can call useWeapon method like weapon.useWeapon.

  2. Concrete heroes
    Provides specific behavior for each hero.

  3. WeaponStrategy
    Provides common interface for all the strategies. In this way, client code can program to interface not implementation.

  4. Concrete Strategies
    Define concrete implementation for using weapons.

With this structure, our strategies are now decoupled from client code which is easier to maintain.
Also, strategies are interchangeable, we can switch weapons dynamically at runtime.

Structure

Image description

  • Client only see context class.
  • Strategies are decoupled from client code by composition.
  • Context uses strategy object to run actual algorithm e.g. strategy.runAlgorithm().
  • We can define multiple concrete strategies that implements actual algorithms in different way.

Implementation in Java

/*
Content in Strategy pattern
 */
public abstract class Hero {

    private WeaponStrategy weapon;

    public Hero() {
        this.weapon = new NoWeaponStrategy();
    }

    public abstract void greet();

    public void surrender() {
        System.out.println("You lose");
    }

    public WeaponStrategy getWeapon() {
        return weapon;
    }

    public void setWeapon(WeaponStrategy weapon) {
        this.weapon = weapon;
    }
}

Enter fullscreen mode Exit fullscreen mode
/*
Concrete content in Strategy pattern
 */
public class Warrior extends Hero {

    @Override
    public void greet() {
        System.out.println("Die with honor!");
    }
}

Enter fullscreen mode Exit fullscreen mode
/*
Strategy in Strategy pattern
Interface for algorithms implementation
 */
public interface WeaponStrategy {

    void useWeapon();
}

Enter fullscreen mode Exit fullscreen mode
/*
Concrete strategy
 */
public class NoWeaponStrategy implements WeaponStrategy {

    @Override
    public void useWeapon() {
        System.out.println("Can't attack, you need a weapon!");
    }
}

Enter fullscreen mode Exit fullscreen mode
/*
Concrete strategy
 */
public class AxeStrategy implements WeaponStrategy {

    @Override
    public void useWeapon() {
        System.out.println("Chopping with an axe!");
    }
}

Enter fullscreen mode Exit fullscreen mode
/*
Client can use different strategies (or algorithms) dynamically
 */
public class Client {

    public static void main(String[] args) {
        Hero warrior = new Warrior();
        // warrior hasn't equipped a weapon
        warrior.getWeapon().useWeapon();
        // warrior equips an axe
        warrior.setWeapon(new AxeStrategy());
        warrior.getWeapon().useWeapon();
    }
}

Enter fullscreen mode Exit fullscreen mode

Output:

Can't attack, you need a weapon!
Chopping with an axe!
Enter fullscreen mode Exit fullscreen mode

Notice warrior has used NoWeaponStrategy at the beginning, then by calling setWeapon method, warrior changed his strategy to AxeStrategy. Thus, it's proven that Strategy pattern let us to change algorithm at runtime.

Pitfalls

  • Since client code configures strategy for a context, client needs to know each strategy implementation.

You can check all the design pattern implementations here.
GitHub Repository


P.S.
I'm new to write tech blog, if you have advice to improve my writing, or have any confusing point, please leave a comment!
Thank you for reading :)

Top comments (2)

Collapse
 
tripleo profile image
tripleo • Edited
  1. ~+1
  2. You did not show the problem.
  3. (nit) put the markdown on github too.
Collapse
 
sota_333ad4b72095606ab40c profile image
Sota • Edited

Hi tripleo, thank you for your comment!

  1. sorry I'm not sure what does this mean.
  2. Yeah, I wrote the problem but that wasn't main point of Strategy pattern. I edited my post.
  3. I created my README on github profile, thank you for informing me!