C language and design pattern - strategy pattern

Strategy mode

"Sun Quan saw Liu Bei's ambition to rise up and kill him. It would make people all over the world despise him. He wanted to beat him. What could he do? Sun Quan had a sister, sun Shangxiang, who was going to recruit Liu Bei as a son-in-law, and then Sun Quan tried to put Liu Bei under house arrest. Sun Quan's idea was still very simple! He didn't let you Liu Bei go back to Xichuan, and then I Dongwu did whatever I wanted It is not impossible to seize Jingzhou and swallow Xichuan. Soochow's idea is good, but there are more resourceful and invincible Zhuge Liang in the middle. He had predicted that Soochow would do this. Therefore, before Liu Bei went to Soochow to recruit relatives, he specially awarded three brochures to the best man Zhao Yun, saying that it was "to solve difficult problems according to heaven's secrets"

  1. Three brocade bags
    1. Ask Qiao Guolao for help (it's a back door)
    2. Ask Wu Guotai to release (complain)
    3. Mrs. sun is dead
  2. Executor
    1. Zhao Yun

What are the similarities between the three strategies? They all tell Zhao Yun how to do it, that is, one of the three strategies is to implement. Of course, the specific content of each strategy is different;

Thinking of this, we have a design idea: the three tricks should realize the same interface;

 

//Smart interface
typedef struct _IStrategy
{	
	//Every trick has an executable method
	void (*operate)();
}IStrategy;

Specific implementation of the coup:

void operate1()
{
	printf("Ask Qiao Guolao for help,\
		Let Wu Guotai put pressure on Sun Quan!");
}

void operate2()
{
	printf("Ask Wu Guotai to turn on the green light and let it go!");
}

void operate3()
{
	printf("After Mrs. sun breaks, stop the pursuers!");
}

//Specific implementation of the clever plan
struct _IStrategy BackDoor =
{
	.operate = operate1,
};

struct _IStrategy GivenGreenLight =
{
	.operate = operate2,
};

struct _IStrategy BlockEnemy =
{
	.operate = operate3,
};

 

  1. There are all three tricks, and there are two supporting roles missing
    1. Brocade bag -- storage place
    2. Zhao Yun -- executor

//Encapsulation role
typedef struct _Context
{
	IStrategy *pIStrategy;

}Context;

void operate(IStrategy *pIStrategy)
{
	if(NULL == pIStrategy)
		return;
	pIStrategy->operate();
}

// According to Zhuge Liang's instructions, the clever plans were disassembled in turn
void ZhaoYun
{
	Context con;
	
	printf("Just arrived in the state of Wu and demolished the first one\n");
	con.pIStrategy = &BackDoor;
	operate(con.pStrategy); //Disassembly execution
	
	printf("Liu Bei is so happy that he doesn't think of Shu. He takes down the second one\n");
	con.pIStrategy = &GivenGreenLight;
	operate(con.pStrategy); //Find a way back to Shu
	
	printf("Sun Quan's soldiers came and opened the third brocade bag\n");
	con.pIStrategy = &BlockEnemy;
	operate(con.pStrategy); //Mrs. sun withdrew
}

Strategy Pattern definition:

Define a family of algorithms,encapsulate each one,and make them interchangeable. (define a set of algorithms, encapsulate each algorithm and make them interchangeable)

  1. The policy pattern uses the object-oriented inheritance and polymorphism mechanism, which is very easy to understand and master. Let's look at the three roles of the policy pattern:
    1. Context encapsulation role: also known as context role, it serves as a connecting encapsulation, shields the direct access of high-level modules to policies and algorithms, and encapsulates possible changes
    2. Strategy Abstract policy role: an abstraction of a policy or Algorithm family, usually an interface, that defines the methods and attributes that each policy or Algorithm must have. [Algorithm: Algorithm]
    3. Concrete strategy specific policy role: implement operations in abstract policies

Policy mode C + + implementation:

//Abstract policy roles
class Strategy
{
public:
  virtual void doSomething(){};
};

//Specific policy roles
class ConcreteStrategy1:public Strategy
{
public:
  void doSomething()
  {
    cout << "Algorithm for specific strategy 1"<<endl;
  }
};

class ConcreteStrategy2:public Strategy
{
public:
  void doSomething()
  {
    cout << "Algorithm of specific strategy 2"<<endl;
  }
};

//Encapsulation role
class Context
{
private:
  Strategy * pStrategy;

public:
  Context(Strategy * pStrategy)
  {
		this.pStrategy = pStrategy;
	}

  void doAnything()
  {
		this.pStrategy->doSomething();  
  }
};

void client
{
  Strategy * pStrategy1 = new ConcreteStrategy1();
  Context *con = new Context(pStrategy1);
  con->doAnything();
}

Policy mode C implementation:

//Abstract policy roles
typedef struct _Strategy
{
	void (*doSomething)();
}Strategy;

void doSomething1()
{
	printf("Algorithm for specific strategy 1");
}

void doSomething2()
{
	printf("Algorithm of specific strategy 2");
}

//Specific policy roles
struct _Strategy ConcreteStrategy1 =
{
	.doSomething = doSomething1,
};

struct _Strategy ConcreteStrategy2 =
{
	.doSomething = doSomething2,
};



//Encapsulation role
typedef struct _Context
{
  Strategy *pStrategy;

}Context;

void doAnything(Strategy *pStrategy)
{
	if(NULL == pStrategy)
		return;
	pStrategy->doSomething();
}


void client
{
  Strategy *pStrategy1 = &ConcreteStrategy1;
	
  Context con;
	con.pStrategy = pStrategy1;
	
	doAnything(con.pStrategy);
}

(1) The algorithm can be switched freely

This is defined by the policy pattern itself. As long as the abstract policy is implemented, it becomes a member of the policy family. It is encapsulated by encapsulating roles to ensure that "freely switchable" policies are provided externally.

(2) Avoid using multiple conditional judgments

If there is no strategy model, let's think about what it would be like? A policy family has five policy algorithms. One will use policy a and the other will use policy B. how to design? Use multiple conditional statements? Multiple conditional statements are not easy to maintain, and the probability of error is greatly enhanced. After using the policy mode, other modules can decide which policy to adopt. The access interface provided by the policy family is the encapsulated class, which simplifies the operation and avoids the judgment of conditional statements.

(3) Good scalability

This is not even an advantage, because it is too obvious. It is too easy to add a strategy to the existing system. As long as the interface is implemented, there is no need to modify anything else. It is similar to a repeatedly removable plug-in, which greatly conforms to the OCP principle.

(1) Increased number of policy classes

Each strategy is a class, the possibility of reuse is very small, and the number of classes increases.

(2) All policy classes need to be exposed

The upper module must know what strategies are available before deciding which strategy to use. This is contrary to the Demeter's law. I just want to use a strategy. Why should I understand this strategy? What's the point of your encapsulation class? This is a disadvantage of the original strategy model. Fortunately, we can use other models to correct this defect, such as factory method model, agent model or meta model.

  1. Multiple classes have only slightly different scenarios in algorithm or behavior
  2. The algorithm requires free switching scenes
  3. Scenarios that need to mask algorithm rules: just pass in the name of the algorithm

Keywords: Design Pattern

Added by senyo on Thu, 13 Jan 2022 22:20:56 +0200