Strategie (englisch strategy) ist im Bereich der Softwareentwicklung ein Entwurfsmuster und gehört zur Kategorie der Verhaltensmuster (englisch behavioral design patterns). Die Strategie definiert eine Familie austauschbarer Algorithmen.[1] Es ist eines der sogenannten GoF-Muster (Gang of Four, siehe Viererbande).
Strategie-Objekte werden ähnlich wie Klassenbibliotheken verwendet. Im Gegensatz dazu handelt es sich jedoch nicht um externe Programmteile, sondern um integrale Bestandteile des eigentlichen Programms, die deshalb als eigene Objekte definiert wurden, damit sie durch andere Algorithmen ausgetauscht werden können.
Meistens wird eine Strategie durch Klassen umgesetzt, die eine bestimmte Schnittstelle implementieren. In Sprachen wie Smalltalk, in denen auch der Programmcode selbst in Objekten abgelegt werden kann, kann eine Strategie aber auch durch solche Code-Objekte realisiert werden.
Die Verwendung von Strategien bietet sich an, wenn
Die Klasse Strategie
definiert nur eine Schnittstelle (interface) für alle unterstützten Algorithmen. Die Implementierung der eigentlichen Algorithmen finden sich erst in den Ableitungen wieder (konkrete Strategie).
Der Kontext
hält eine Variable der Schnittstelle Strategie, die mit einer Referenz auf das gewünschte Strategieobjekt belegt ist. Auf diese Weise wird der konkrete Algorithmus über die Schnittstelle eingebunden und kann bei Bedarf selbst zur Laufzeit noch dynamisch gegen eine andere Implementierung ausgetauscht werden.
Als Beispiel kann ein Steuerberechnungsprogramm dienen, das die Berechnung von Steuersätzen möglichst in Strategie-Objekte auslagern sollte, um einfach länderabhängig konfigurierbar zu sein.
Ein anderes Beispiel wäre die Speicherung eines Dokuments oder einer Grafik in verschiedenen Dateiformaten.
Auch ein Packer, der verschiedene Kompressionsalgorithmen unterstützt, kann mit Hilfe von Strategie implementiert sein. Bei Java wird das Entwurfsmuster zum Beispiel zur Delegierung des Layouts von AWT-Komponenten an entsprechende LayoutManager (BorderLayout, FlowLayout etc.) verwendet.
Weitere Beispiele (außerhalb der OOP-Welt):
//
// g++ -std=c++11 strategy.cpp -o strategy
//
#include <iostream>
#include <memory>
class Strategy {
public:
virtual void operator()() = 0;
virtual ~Strategy() = default;
};
class Context {
std::unique_ptr<Strategy> strat_;
public:
Context() : strat_(nullptr) {}
void setStrategy(std::unique_ptr<Strategy> strat) { strat_ = std::move(strat); }
void strategy() { if (strat_) (*strat_)(); }
};
class Strategy1 : public Strategy {
public:
void operator()() override { std::cout << "Foo\n"; }
};
class Strategy2 : public Strategy {
public:
void operator()() override { std::cout << "Bar\n"; }
};
class Strategy3 : public Strategy {
public:
void operator()() override { std::cout << "FooBar\n"; }
};
int main() {
Context c;
c.setStrategy( std::unique_ptr<Strategy>(new Strategy1) );
c.strategy();
c.setStrategy( std::unique_ptr<Strategy>(new Strategy2) );
c.strategy();
c.setStrategy( std::unique_ptr<Strategy>(new Strategy3) );
c.strategy();
}
class Client {
public static void main(final String[] ARGS) {
final Context c = new Context();
c.setStrategy(new StrategyA());
c.doSomething(); // "Strategie A"
c.setStrategy(new StrategyB());
c.doSomething(); // "Strategie B"
}
}
class Context {
private Strategy strategy = null;
public void setStrategy(final Strategy STRATEGY) {
strategy = STRATEGY;
}
public void doSomething() {
if (strategy != null) {
strategy.execute();
}
}
}
interface Strategy {
void execute();
}
class StrategyA implements Strategy {
public void execute() {
System.out.println("Strategie A");
}
}
class StrategyB implements Strategy {
public void execute() {
System.out.println("Strategie B");
}
}
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
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