Strategy (Policy) Pattern is translated into a Policy mode. It is one of 23 modes in Gof's classic design mode. This article will reference the actual project scenario to use the policy mode to transform the actual project, to illustrate the purpose of the Policy mode.
The following uses Strategy instead of Strategy (Policy) Pattern.
The core of Strategy:Strategy allows algorithms or objects to change independently of customers who use them.
How to use Strategy: Extract the variable part of the process to a separate "policy" object, and separate the rule from the behavior it controls. Strategy implements rules or replaceable processes. Multiple implementations of Strategy indicate different methods of completing the process.
Strategy standard UML:
Edit By: http://yuml.me/0d337825
Example of the company's actual project:
Edit By: http://yuml.me/1a72b147
The AppBase base class implements the public Animation method. The Animation method achieves the AppBase UI effect, while PhotoApp and VideoApp can overwrite and implement their own OpenApp and CloseApp methods respectively, that is, public parts are reused and personalized extensions of different sub-classes are supported. From the actual use results, it was a good design at that time.
However, over time, more and more user needs are integrated into the project team. The main requirement is that the interface needs a more dazzling effect. In response to the requirement, the project team did not dare to neglect it. After the study, we decided to add some methods to the Base class and rewrite the Animation. All subclasses that inherit the Base class have new UI rendering features.
After some hitting, we found that the effects of each sub-App were unsatisfactory, such as Scale by X, Y axis, and Rotate by X axis. In the end, we realized that using inheritance is not a method, because the requirements for presentation are constantly changing. Today we can use Modern Style to change you to Ribbon Style and learn 360 desktops the day after tomorrow... Therefore, future changes will be very frequent and unpredictable. If we simply rewrite and modify them one by one, we will obviously not be able to cope with the changes ~
At this time, I am confused. Why can't I support reuse well when the design implementation for new requirements is constantly pouring in?
Afterwards, I tried to extract Animation into an interface and abstract it into Scale and Rotate. Obviously, if there are dozens of apps, You need to repeat the interface implementation method. If a method requires a slight modification, you may need to modify it in multiple places. Obviously, this solution can be rejected.
We know that not all apps require Scale and Rotate. Therefore, inheritance is not the correct method. Although the method using an interface above can solve some problems, it completely destroys reuse. Another problem is also very important. The Scale, Rotate, and other behaviors of each App are not necessarily the same.
Write it here, throw the prelude problem through the actual scenario, and the strategy mode can be officially launched. The so-called "no change to the plan" means that face-to-face changes are the right way to solve the problem. AppBase behavior in the scenario continues to change in the subclass, therefore, it is inappropriate to make all subclasses have the behavior of the base class. The method of using the above interface breaks down code reuse. Now we need two design principles to solve the problem:
1. Find the change and encapsulate it. Later you can modify or extend the changed part of the package without affecting other parts.
2. Interface-oriented programming, not implementation-oriented programming.
Now, let's do the following:
1. added two instance variables for the AppBase class, scaleBehavior and rotateBehavior, to implement the scaling and rotation actions in the new design;
2. Remove the Animation method from AppBase and add the merge mscale () and merge mrotate () methods;
3. Consider When to initialize ScaleBehavior and RotateBehavior variables, and add SetScaleBehavior () and SetRotateBehavior () to set the variable value, so that the AppBase behavior can be dynamically changed at runtime;
Edit-By: http://yuml.me/d4b87f1a
This implementation is the application of Strategy Mode.
Context:
- Use the algorithms provided by ConcreteStrategy, such as the ScaleWithX () method in the preceding scenario;
- The base class maintains a Strategy instance;
- The base class is responsible for dynamically setting specific implementation algorithms of Strategy during runtime. For example, SetScaleBehavior ();
- The base class is responsible for interaction and data transmission with Strategy;
Strategy:
A public interface is defined. Different algorithms implement this interface in different ways. Context uses this interface to call different algorithms, which are generally implemented using interfaces or abstract classes.
ConcreteStrategy:
Implements the interfaces defined by Strategy and provides specific algorithm implementations.
Each design pattern solves practical problems in a specific scenario. There are many online introductions on the advantages and scenarios of Strategy, so I will not list them any more.
Disadvantages of Strategy
Because each specific policy class (ConcreteStrategy) generates a new class, it will increase the number of classes to be maintained by the application.
Finally, two design principles are described in the article. Here we add another important design principle:
The combination of objects is preferred, rather than class inheritance (Favor composition over inheritance ). How can we understand this sentence? You can Google this article and I will not describe it.
PS:
This article only references the actual project as a case example explained by Strategy. The reconstruction of the actual project should be based on the actual design requirements, and does not take this article as any guide.