Strategy (design pattern)
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
Declaration by the actors
The class Strategie
defines only one interface ( interface ) for all supported algorithms. The implementation of the actual algorithms can only be found in the derivations ( concrete strategy ).
It Kontext
holds 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
- Video on Implementing the Strategy Design Pattern for .NET Developers
- Strategy Pattern Tutorial with Java Examples
- Behavioral Patterns - Strategy
Individual evidence
- ↑ Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley , 1996, ISBN 3-8273-1862-9 , pp. 373 .