Strategy (design pattern)

from Wikipedia, the free encyclopedia

The strategy ( English strategy ) is a design pattern in the field of software development . It belongs to the category of behavioral patterns (English behavioral design patterns ) and defines a family of interchangeable algorithms . It is one of the so-called GoF patterns.

use

Strategy objects are used in a similar way to class libraries . In contrast to this, however, it is not about external program parts, but rather integral parts of the actual program, which have therefore been defined as separate objects so that they can be exchanged by other algorithms.

Most of the time, a strategy is implemented through classes that implement a specific interface . In languages ​​such as Smalltalk , in which the program code itself can also be stored in objects , a strategy can also be implemented using such code objects.

Using strategies lends itself to when

  • many related classes differ only in their behavior.
  • different (interchangeable) variants of an algorithm are required.
  • Data should be hidden from clients within an algorithm.
  • different behaviors are firmly integrated within a class (mostly via multiple branches), but
    • the algorithms used are to be reused or
    • the class should be made more flexible.

UML diagram

Strategy.png

Declaration by the actors

The class Strategiedefines only one interface ( interface ) for all supported algorithms. The implementation of the actual algorithms can only be found in the derivations ( concrete strategy ).

It Kontextholds a variable of the strategy interface that is assigned a reference to the desired strategy object. In this way, the specific algorithm is integrated via the interface and, if necessary, can be dynamically exchanged for another implementation even at runtime.

advantages

  • A family of algorithms is defined.
  • It is possible to choose from different implementations and this increases flexibility and reusability.
  • Multiple branches can be avoided and this increases the overview of the code.
  • Strategies offer an alternative to subclassing the contexts.

disadvantage

  • Clients need to know the different strategies in order to be able to choose between them and to initialize the context.
  • Compared to the implementation of the algorithms in the context, an additional communication effort between strategy and context arises.

example

A tax calculation program can serve as an example, which should, if possible, outsource the calculation of tax rates to strategy objects, so that it can be easily configured depending on the country.

Another example would be saving a document or graphic in different file formats.

A packer that supports various compression algorithms can also be implemented using a strategy. With Java, the design pattern is used, for example, to delegate the layout of AWT components to the corresponding LayoutManager (BorderLayout, FlowLayout, etc.).

Further examples (outside the OOP world):

Program examples

Example in C ++

//
// g++ -std=c++11 strategy.cpp -o strategy
//
#include <iostream>
#include <memory>

class Strat {
public:
    virtual void operator()() = 0;
    virtual ~Strat() = default;
};

class Kontext {
    std::unique_ptr<Strat> strat_;
public:
    Kontext() : strat_(nullptr) {}
    void setStrategy(std::unique_ptr<Strat> strat) { strat_ = std::move(strat); }
    void strategy() { if (strat_) (*strat_)(); }
};

class Strategy1 : public Strat {
public:
    void operator()() override { std::cout << "Foo\n"; }
};

class Strategy2 : public Strat {
public:
    void operator()() override { std::cout << "Bar\n"; }
};

class Strategy3 : public Strat {
public:
    void operator()() override { std::cout << "FooBar\n"; }
};


int main() {
    Kontext k;

    k.setStrategy( std::unique_ptr<Strat>(new Strategy1) );
    k.strategy();

    k.setStrategy( std::unique_ptr<Strat>(new Strategy2) );
    k.strategy();

    k.setStrategy( std::unique_ptr<Strat>(new Strategy3) );
    k.strategy();
}

Java

class Klient {
	public static void main(final String[] ARGS) {
		final Kontext k = new Kontext();

		k.setStrategie(new KonkreteStrategieA());
		k.arbeite();	// "Weg A"
		k.setStrategie(new KonkreteStrategieB());
		k.arbeite();	// "Weg B"
	}
}


class Kontext {
	private Strategie strategie = null;

	public void setStrategie(final Strategie STRATEGIE) {
		strategie = STRATEGIE;
	}

	public void arbeite() {
		if (strategie != null) {
			strategie.algorithmus();
		}
	}
}

interface Strategie {
	void algorithmus();
}

class KonkreteStrategieA implements Strategie {
	public void algorithmus() {
		System.out.println("Weg A");
	}
}

class KonkreteStrategieB implements Strategie {
	public void algorithmus() {
		System.out.println("Weg B");
	}
}

Ruby

class Context
  private
  attr_writer :strategy

  public
  def initialize(strategy)
    @strategy = strategy
  end

  def execute
      unless @strategy.respond_to?('execute')
        raise NotImplementedError,'Strategie-Objekt antwortet nicht auf die execute-Methode'
      end
      @strategy.execute
  end
end

class StrategyA
  def execute
     puts 'Der normale Weg'
  end
end

class StrategyB
  def execute
     puts 'Ein anderer Weg'
  end
end

class StrategyC
  def execute
     puts 'Noch ein anderer Weg'
  end
end

a = Context.new(StrategyA.new)
a.execute
# Der normale Weg

b = Context.new(StrategyB.new)
b.execute
# Ein anderer Weg

c = Context.new(StrategyC.new)
c.execute
# Noch ein anderer Weg

python

class Context:
    def __init__(self, strategy):
        self.strategy = strategy

    def execute(self, a, b):
        return self.strategy(a, b)


class AddStrategy:
    def __call__(self, a, b):
        return a + b

class SubStrategy:
    def __call__(self, a, b):
        return a - b

context = Context(AddStrategy())
print('4 + 3 =', context.execute(4, 3))
# 4 + 3 = 7

context.strategy = SubStrategy()
print('4 - 3 =', context.execute(4, 3))
# 4 - 3 = 1

Related design patterns

Web links

Individual evidence

  1. Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley , 1996, ISBN 3-8273-1862-9 , pp. 373 .