Strategy mode
In GOF's book "design patterns: the foundation of reusable object-oriented software", the strategic patterns are as follows: define a series of algorithms, encapsulate them one by one, and make them interchangeable. This pattern allows the algorithm to change independently of the customers who use it.
In order to adapt to different requirements, the strategy mode only encapsulates the change point, which is the algorithm to achieve different requirements. However, users need to know the specific situation of various algorithms. Just like the above overtime pay, different overtime situations have different algorithms. We can't hard code the algorithm of calculating salary in the program, but we can change it freely. This is the strategic model.
UML class diagram
Strategy: defines the common interface for all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy;
Concrete Strategy: the specific algorithm to implement the Strategy interface;
Context: use a ConcreteStrategy object to configure; maintain a reference to the Stategy object, and define an interface for Stategy to access its data.
Use occasion
Use Strategy mode when:
- Many related classes simply differ in behavior. Policy provides a way to configure a class with one of multiple behaviors;
- Different variants of an algorithm need to be used;
- The algorithm uses data that the customer should not know. Policy patterns can be used to avoid exposing complex, algorithm related data structures;
- A class defines multiple behaviors, and these behaviors appear in the form of multiple conditional statements in the operation of the class. Instead of these conditional statements, move the relevant conditional branches into their respective Strategy classes. (is it and State mode It's a little bit the same
code implementation
First of all, the simplest strategy mode is implemented. The code is as follows:
#include <iostream> using namespace std; // The abstract strategy class Strategy { public: virtual void AlgorithmInterface() = 0; }; class ConcreteStrategyA : public Strategy { public: void AlgorithmInterface() { cout<<"I am from ConcreteStrategyA."<<endl; } }; class ConcreteStrategyB : public Strategy { public: void AlgorithmInterface() { cout<<"I am from ConcreteStrategyB."<<endl; } }; class ConcreteStrategyC : public Strategy { public: void AlgorithmInterface() { cout<<"I am from ConcreteStrategyC."<<endl; } }; class Context { public: Context(Strategy *pStrategyArg) : pStrategy(pStrategyArg) { } void ContextInterface() { pStrategy->AlgorithmInterface(); } private: Strategy *pStrategy; }; int main() { // Create the Strategy Strategy *pStrategyA = new ConcreteStrategyA; Strategy *pStrategyB = new ConcreteStrategyB; Strategy *pStrategyC = new ConcreteStrategyC; Context *pContextA = new Context(pStrategyA); Context *pContextB = new Context(pStrategyB); Context *pContextC = new Context(pStrategyC); pContextA->ContextInterface(); pContextB->ContextInterface(); pContextC->ContextInterface(); if (pStrategyA) delete pStrategyA; if (pStrategyB) delete pStrategyB; if (pStrategyC) delete pStrategyC; if (pContextA) delete pContextA; if (pContextB) delete pContextB; if (pContextC) delete pContextC; }
In the actual operation process, we will find that in the main function, that is, when the client uses the policy mode, a lot of strategies will be created, which increases the pressure on the client and the complexity of the client. Then, we can learn from the simple factory model to make the strategic model and Simple factory mode The code is as follows:
#include <iostream> using namespace std; // Define the strategy type typedef enum StrategyType { StrategyA, StrategyB, StrategyC }STRATEGYTYPE; // The abstract strategy class Strategy { public: virtual void AlgorithmInterface() = 0; virtual ~Strategy() = 0; // Thanks for hellowei's bug. Please refer to the comments for details }; Strategy::~Strategy() {} class ConcreteStrategyA : public Strategy { public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyA." << endl; } ~ConcreteStrategyA(){} }; class ConcreteStrategyB : public Strategy { public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyB." << endl; } ~ConcreteStrategyB(){} }; class ConcreteStrategyC : public Strategy { public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyC." << endl; } ~ConcreteStrategyC(){} }; class Context { public: Context(STRATEGYTYPE strategyType) { switch (strategyType) { case StrategyA: pStrategy = new ConcreteStrategyA; break; case StrategyB: pStrategy = new ConcreteStrategyB; break; case StrategyC: pStrategy = new ConcreteStrategyC; break; default: break; } } ~Context() { if (pStrategy) delete pStrategy; } void ContextInterface() { if (pStrategy) pStrategy->AlgorithmInterface(); } private: Strategy *pStrategy; }; int main() { Context *pContext = new Context(StrategyA); pContext->ContextInterface(); if (pContext) delete pContext; }
In the above code, in fact, we may see more application of simple factory mode. We combine the simple factory mode with the policy mode to make the client easier to use.
summary
The strategy mode and the state mode are the same; the state mode focuses on the change of the state and the different behaviors executed in different states; the strategy mode focuses on the same action, and the different algorithms to realize the behavior, and different strategies encapsulate different algorithms. The strategy pattern is applicable to the realization of a certain function, and the algorithm to achieve this function is often changed. In the actual work, encountered the actual scene, may have a deeper understanding. For example, we do a certain system, which can be applied to various databases. We all know that the way to connect a certain database is not the same. We can also say that the "algorithm" to connect the database is not the same. In this way, we can use the policy pattern to realize different strategies of connecting to the database, so as to realize the dynamic transformation of the database.