In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly explains "how to locate the strategy according to the different combinations of p1, p2, p3 and so on". The content of the explanation in this article is simple and clear, and it is easy to learn and understand. let's study and learn "how to make strategic positioning according to the different combinations of p1, p2, p3 and so on."
Problem background
Recently, a requirement has been developed that the interface needs to give the result data according to the corresponding business strategy according to the different combinations of p1, p2, p3 and version input parameters.
Since the interface has been developed for three times, everyone tends to add it without deletion or modification in order to be compatible with the old business logic when developing a new one.
So this code has produced some "bad smell", and the function entry jumps to the new business logic method by constantly adding "guard statements" to determine version.
The business logic of each phase also forms different branch logic through the if-else combination of p1, p2 and p3.
This is my simplified expression, in short, at the beginning for my new classmate, it really took some work to sort out this business code.
Moreover, this logic is equivalent to a general business capability. In the future, there must be five, six, and N periods of demand coming in, and the value of input parameters will continue to expand, so expanding in the existing way will only make the "bad taste" more and more serious.
To sum up, the problems facing the current scenario are:
How to solve the interface upgrade and easily develop the new version of business logic while ensuring compatibility with the old version?
How to locate the strategy according to the different combinations of input parameters p1, p2, p3, etc.
Solution idea
When thinking about a solution, it is easy to think of two design patterns that can optimize similar scenarios: the chain of responsibility pattern and the strategy pattern.
Responsibility chain model
The chain of responsibility pattern implements a step-by-step processing similar to the "pipeline" structure, which is usually a chain structure that connects the different implementations of the "abstract processor".
If the current node can handle the task, it will dispose of it directly, and if it cannot, it will be delegated to the next node in the chain of responsibility, and so on until a node can handle the task.
We can use the responsibility chain pattern to isolate different version business logic, such as node 1 processing version=1 requests, node 2 processing version=2 requests, and so on.
But the problem is that the scenarios we encounter need to be routed to different downstream nodes according to a certain strategy. This is what the strategic model is good at solving.
Strategy mode
The purpose of the policy pattern is to decouple the use of the algorithm from the definition so that it can be routed to different policy classes according to the rules.
We can use the policy pattern to solve the scenario where different business logic is executed according to different parameter combinations. However, only one layer of policy routing can not meet the task processing requirements in our scenario. Hierarchical processing of requests is what the chain of responsibility model is good at again.
As you can see, the two design patterns are not completely in line with the current scenario: the responsibility chain pattern can achieve step-by-step delegation, but each level cannot be routed to different processors like the policy pattern; the policy pattern usually has only one layer of routing. it is not easy to realize the policy combination of multiple parameters.
So we can naturally think: is it possible to combine the two models?
Generalized responsibility chain model: responsibility tree model
The combination of responsibility chain and strategy model becomes a generalized responsibility chain model, which is called "responsibility tree model" for short.
This model can not only complete the step-by-step delegation of the task, but also select different downstream strategies at any level to deal with.
So the question is, how to solve the previous problems through the responsibility tree model?
First of all, let's look at how to solve the first problem, the isolation and compatibility of new and old interfaces: you can use the logic of each version of the interface as a different implementation of the first layer on the responsibility tree, such as corresponding to the Strategy1, Strategy2, and Strategy3 nodes in the figure above.
In this way, at the interface entrance, the policy is first routed to different branches. If no node is hit, the error is no longer returned directly to the downstream delegate.
Then the second problem, the combination of parameters is located on the implementation of different strategies: in the same way of thinking, one parameter corresponds to the routing of one layer on the responsibility tree, and the different values of this parameter can be routed to different implementations of the next layer. It is very convenient to expand the enumeration values of new input parameters and even expand new input parameters.
Optimize the income
After refactoring this business through the "responsibility tree model", you can reap the following benefits:
The labor cost is reduced in subsequent iterations.
The code structure is clearer and the maintainability is improved: without the jumps of various "defense statements" & the huge method of poor maintainability, the function can converge within the ideal 50 lines.
The subsequent new requirement modification code is not easy to make mistakes: isolation between policies, you don't need to read the big function completely and then modify it, you just need to add a route + a new policy implementation method without a brain.
The problem is easy to locate: also because of the isolation between policies, debugging can directly locate the business logic code of the specified policy, without the need for sentence-by-sentence troubleshooting.
I believe that students with development experience should have the experience that even the code they have written will be forgotten without looking at it for a while, and when there are changes, they have to go through the logic of the code. If the documentation and comments are not well written, it will be even more sour. Therefore, it is very important to decompose and decouple giant functions.
Abstract framework
Although the problem encountered in my requirements development has been solved through the "responsibility tree pattern", similar problems are still common.
In the spirit of helping people (zi), I further abstracted the responsibility tree pattern into a general framework to facilitate people to plant trees quickly when they encounter similar problems.
The framework consists of a Router and a Handler:
Router is an abstract class that defines how to route to multiple child nodes downstream.
Handler is the interface that implements the business logic of each node.
We can easily assemble the whole tree structure through the combination of Router and Handler.
We can see the following points from the picture:
Except for the root node (entry), each node implements the Handler interface. The root node inherits only the Router abstract class.
All leaf nodes implement only the Handler interface and do not need to inherit the Router abstract class (no further delegation is required).
All the nodes except the root node and the leaf node are the Handler of the upper layer and the Router of the lower layer.
So let's not say much, let's take a look at the framework code first.
① AbstractStrategyRouter Abstract Class:
The general "policy tree" framework implements distribution and delegation through a tree structure, and each layer distributes delegates downward through specified parameters until the final executor is reached. * the framework contains two classes: {@ code StrategyHandler} and {@ code AbstractStrategyRouter} * where the policy is distributed by implementing the {@ code AbstractStrategyRouter} abstract class, and the policy is implemented by implementing the {@ code StrategyHandler} interface. * nodes such as layer 2 An and B are both policy implementers of Root nodes and distributors of policies A1, A2, B1 and B2. Such nodes only need to * inherit {@ code StrategyHandler} and implement {@ code AbstractStrategyRouter} interfaces at the same time. * * +-+ * | Root |-layer 1 policy entry * +-+ * /\-Policy distribution according to input parameter P1 * / \ * +-+-+ * | A | | B |-implementation of different policies at layer 2 * +-+-+ * / /\-policies based on input parameter P2 Distribute * /\ * +-- + * | A1 | | A2 | B1 | | B2 |-implementation of different policies at layer 3 * +-- * @ author * @ date * @ see StrategyHandler * / @ Component Public abstract class AbstractStrategyRouter {/ * Policy Mapper Routes to the corresponding policy handler according to the specified input parameter. Input parameter type of * * @ param policy * @ param policy return value type * / public interface StrategyMapper {/ * get the corresponding policy handler according to the input parameter. It can be implemented through if-else or Map. * * @ param param input parameter * @ return policy handler * / StrategyHandler get (T param); register distribution policy Mapper * / @ PostConstruct private void abstractInit () {strategyMapper = registerStrategyMapper (); Objects.requireNonNull (strategyMapper, "strategyMapper cannot be null") when the class private StrategyMapper strategyMapper; / * is initialized } @ Getter @ Setter @ SuppressWarnings ("unchecked") private StrategyHandler defaultStrategyHandler = StrategyHandler.DEFAULT; / * execute the policy. The framework automatically distributes the policy to the downstream Handler for processing * * @ param param input parameter * @ the return value given by the downstream executor * / public R applyStrategy (T param) {final StrategyHandler strategyHandler = strategyMapper.get (param) If (strategyHandler! = null) {return strategyHandler.apply (param);} return defaultStrategyHandler.apply (param);} / * Abstract method, which requires subclass implementation policy distribution logic * * @ return distribution logic Mapper object * / protected abstract StrategyMapper registerStrategyMapper ();}
Inherit AbstractStrategyRouter
If the routing logic of the child node is relatively simple, it can be distributed directly through if-else. Of course, if you want to better performance, adapt to more complex distribution logic can also use Map and so on to save the mapping.
For the Router node that implements the abstract class, you only need to call its public R applyStrategy (T param) method to get the expected output of the node.
The framework automatically passes the param to the corresponding child nodes according to the defined routing logic, and then the child nodes continue to distribute down until the leaf node or a layer of business output can be given. This process is somewhat similar to the idea of recursion or partition.
② StrategyHandler API:
/ * * @ author * @ date * / public interface StrategyHandler {@ SuppressWarnings ("rawtypes") StrategyHandler DEFAULT = t-> null; / * apply strategy * * @ param param * @ return * / R apply (T param);}
StrategyHandler should be implemented except for the root node.
So it is no longer necessary to inherit AbstractStrategyRouter at the same time.
For other middle-tier nodes in the responsibility tree, you need to inherit both the Router abstract class and the implementation Handler interface.
In the R apply (T param); method, we first intercept some abnormal input parameters and follow the fail-fast principle to avoid passing the interceptable errors from this layer to the next layer. At the same time, we should also avoid "ultra vires" to do intercept verification that is not the responsibility of this layer, avoid coupling, and dig holes for later business development.
After intercepting the logic, you can directly call the public R applyStrategy (T param) method of its own Router and route it to the downstream node.
Thank you for your reading. the above is the content of "how to locate the strategy according to the different combinations of p1, p2, p3 and so on". After the study of this article, I believe you have a deeper understanding of how to locate the strategy according to the different combinations of p1, p2, p3, etc., and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.