In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the relevant knowledge of "what is the implementation of the responsibility chain design pattern". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Responsibility chain design pattern
Schema definition
The request is processed on a chain, and the receiver on the chain decides whether to continue to pass it back or interrupt the current processing process.
Applicable scenario
Suitable for multi-node process processing, each node completes its own responsible part, and the nodes do not know the existence of each other, such as the approval flow of OA and the Filter mechanism in Java Web development.
To cite an example in my life, when I rented a house, I met a so-called black intermediary. I felt like God when I rented, but I was like a grandson when I asked him to fix something broken.
The intermediary asked me to find the customer service of the store, the customer service of the store asked me to find the landlord, and the landlord asked me to find her husband, and finally got rid of it (renting a house must find a formal intermediary).
Practical experience
At present, the business I do is the aggregate payment of campus group meals, and the business process is very simple:
Students open the mobile phone payment code to pay.
The cafeteria aunt uses machines to scan the payment code to collect the money.
There is a background in the university canteen that the canteen is subsidized and the food is relatively cheap, so the school is unwilling to allow the public to go to the school canteen to spend money. In view of this, we have added a set of test logic to whether payment is allowed before payment.
It is roughly as follows:
A certain file only allows a certain kind of users to consume, for example, teachers only allow teachers to consume, and students do not allow off-campus users to consume.
A certain stall only allows certain users to spend a few times a day, for example, teachers' canteens only allow students to spend once a day.
Whether to allow non-halal students to spend, such as some halal restaurants, is not allowed to be consumed by non-halal students.
In view of these situations, I have established three types of filters, which are:
SpecificCardUserConsumeLimitFilter: judge whether consumption is allowed by the type of user.
DayConsumeTimesConsumeLimitFilter: judge whether consumption is allowed according to the number of times of daily consumption.
MuslimConsumeLimitFilter: whether non-halal users are allowed to spend.
The judgment logic is to determine whether the current user can spend money in this file through SpecificCardUserConsumeLimitFilter.
If DayConsumeTimesConsumeLimitFilter is allowed to determine whether the consumption times of the day have been used up; if it is not used up, MuslimConsumeLimitFilter will continue to determine whether the current user meets the dining conditions of the halal restaurant. If one of the first three judgments is not satisfied, return in advance.
Some of the codes are as follows:
Public boolean canConsume (String uid,String shopId,String supplierId) {/ / get user information, including type (student: student, teacher: teacher, unknown: unknown user), ethnic group (han: Han, mg: Mongolian) UserInfo userInfo = getUserInfo (uid) / / get consumption restriction information, including whether non-halal consumption is allowed, whether each type of user is allowed to consume, and the number of times allowed to consume ConsumeConfigInfo consumeConfigInfo = getConsumeConfigInfo (shopId,supplierId) / / construct the consumption restriction filter chain ConsumeLimitFilterChain filterChain = new ConsumeLimitFilterChain (); filterChain.addFilter (new SpecificCardUserConsumeLimitFilter ()); filterChain.addFilter (new DayConsumeTimesConsumeLimitFilter ()); filterChain.addFilter (new MuslimConsumeLimitFilter ()) Boolean checkResult = filterChain.doFilter (filterChain, schoolMemberInfo, consumeConfigInfo); / / filterChain.doFilter method public boolean doFilter (ConsumeLimitFilterChain filterChain,UserInfo userInfo, ConsumeConfigInfo consumeConfigInfo) {/ / iterative call filter if (index= cardConsumeConfig.getDayConsumeTimesLimit ()) {return false } / / for the rest, continue to pass return filterChain.doFilter (filterChain, memberInfo, consumeConfig) later;}
Summary: the judgment logic of each constraint is encapsulated into a specific Filter. If the logic of one constraint is modified, it will not affect other conditions. If you need to add new constraints, you only need to reconstruct a Filter to weave into the FilterChain.
Strategic design pattern
Schema definition
Define a series of algorithms, encapsulate each algorithm, and make them interchangeable.
Applicable scenario
The main purpose is to eliminate a large amount of if else code, extract the algorithm logic behind each judgment to the specific policy object, and have no perception to the user when the algorithm logic is modified, only need to modify the internal logic of the policy object.
This kind of policy objects generally implement a common interface and can achieve the purpose of interchange.
Practical experience
A previous requirement of the author is that the user pushes a payment message to the cashier device after scanning the code, and the cashier device will broadcast the message after receiving the message. the logic is very simple, that is, you can call the push platform to push a message to the device.
However, due to historical reasons, the push platforms for some devices are different. Class A devices give priority to XGPush push. If they fail, they need to be downgraded to a long polling mechanism. Class B devices can directly use the self-developed push platform.
Another current situation is that the message formats of Class An and Class B are different (different team development, later integrated).
In view of this, I abstract the PushStrategy API, and its specific implementations are IotPushStrategy and XingePushStrategy, which correspond to the push policies of the self-developed push platform and XGPush platform, respectively. Users can use different push policies for different device types.
Some of the codes are as follows:
/ * push policy * / public interface PushStrategy {/ * * @ param deviceVO device object, buckle device sn, XGPush pushid @ param content, push content, usually json * / public CallResult push (AppDeviceVO deviceVO, Object content) } IotPushStrategy implements PushStrategy {/ * * @ param deviceVO device object, buckle device sn, XGPush pushid @ param content, push content, generally json * / public CallResult push (AppDeviceVO deviceVO, Object content) {/ / the push message Message message = createPushMsg (deviceVO,content) required to create a self-developed push platform / / call the push platform push API IotMessageService.pushMsg (message) }} XingePushStrategy implements PushStrategy {/ * * @ param deviceVO device object, buckle device sn, XGPush pushid @ param content, push content, generally json * / public CallResult push (AppDeviceVO deviceVO, Object content) {/ / push message JSONObject jsonObject = createPushMsg (content) required to create XGPush platform / / call push platform push API if (! XinggePush.pushMsg (message)) {/ / downgrade to long polling.} / * * message push Service * / MessagePushService {pushMsg (AppDeviceVO deviceVO, Object content) {if (A device) {XingePushStrategy.push (deviceVO,content) } else if (B device) {IotPushStrategy.push (deviceVO,content);}
Summary: the push logic of each channel is encapsulated into a specific strategy, and the change of one policy will not affect other policies. Due to the implementation of the common interface, the policies can be replaced with each other and user-friendly.
For example, the task rejection policy in Java ThreadPoolExecutor executes the rejection policy when the thread pool is saturated, and the specific rejection logic is encapsulated in the rejectedExecution of RejectedExecutionHandler.
Template design pattern
Schema definition
The value of the template lies in the definition of the skeleton, the process of problem processing within the skeleton has been defined, the general processing logic is generally implemented by the parent class, and the personalized processing logic is implemented by the subclass.
For example, stir-fried shredded potatoes and fried Mapo tofu, the general logic is:
Cut vegetables
Drain oil
Fried vegetables
Out of the pot
Step 3 is different: stir-fry shredded potatoes with a shovel, but stir-fry Mapo tofu with a spoon, otherwise the tofu will rot (the epidemic stays at home and learns a lot of food).
Working with scen
For the processing flow of different scenarios, part of the logic is universal and can be put into the parent class as a general implementation, while part of the logic is personalized and needs to be individualized by subclasses.
Practical experience
Following the previous example of voice broadcast, we added two new requirements in the later stage:
Trace needs to be added for message push.
Some channels fail to push and need to be retried.
So now the process looks like this:
Trace, start.
The channel is starting to push.
Whether retry is allowed, if retry logic is allowed.
Trace is over.
Of these, 1 and 4 are generic, and 2 and 3 are personalized, so I added a layer of parent policy before the specific push policy, putting generic logic into the parent class.
The modified code is as follows:
Abstract class AbstractPushStrategy implements PushStrategy {@ Override public CallResult push (AppDeviceVO deviceVO, Object content) {/ / 1. Construct span Span span = buildSpan (); / / 2. The push logic of specific channel is implemented by subclass CallResult callResult = doPush (deviceVO, content); / / 3. Whether the retry logic is allowed to be implemented by the subclass, if the retry logic if (! callResult.isSuccess () & & canRetry ()) {doPush (deviceVO, content);} / / 4.trace ends span.finish ()} / / the specific push logic is implemented by the subclass protected abstract CallResult doPush (AppDeviceVO deviceDO, Object content) / / whether to retry the implementation by subclasses. Some channels cannot retry protected abstract boolean canRetry (CallResult callResult) because message reordering has not been done before.} XingePushStrategy extends AbstractPushStrategy {@ Override protected CallResult doPush (AppDeviceVO deviceDO, Object content) {/ / execute push logic} @ Override protected boolean canRetry (CallResult callResult) {return false}}
Summary: the process is defined through the template, the general logic is implemented in the parent class, the repetitive code is reduced, the personalized logic is implemented by the subclass itself, and the modification code between the subclasses does not interfere with each other and will not destroy the process.
Observer design pattern
Schema definition
As the name implies, this model requires two roles: the Observer and the Observable.
When the state of the Observable changes, it informs the Observer,Observer that it generally implements a common type of interface.
For example, when java.util.Observer,Observable needs to notify Observer, you can call the update method of Observer one by one. The success of Observer processing should not affect the process of Observable.
Working with scen
The state change of an object (Observable) needs to notify other objects. The existence of Observer does not affect the processing result of Observable, and the addition or deletion of Observer is not aware of Observable.
For example, in Kafka's message subscription, Producer sends a message to Topic, but there is no need to pay attention to whether it is 1 or 10 Consumer subscriptions to this Topic,Producer.
Practical experience
In the part of the chain of responsibility design pattern, I solved the problem of consumption limit test through three Filter, one of which is used to check the number of consumption. I only read the number of consumption here, so how is the accumulation of consumption completed?
In fact, the accumulation uses the observer mode, specifically, when the trading system receives a successful payment callback, it will publish "payment success events" through Spring's event mechanism.
In this way, subscribers responsible for accumulating consumption times and voice broadcasting will receive "payment success events" and then do their own business logic.
Draw a simple picture to describe:
The code structure is roughly as follows:
/ * * payment callback handler * / PayCallBackController implements ApplicationContextAware {private ApplicationContext applicationContext; / / if you need to implement the ApplicationContextAware interface to obtain applicationContext, the Spring container will call back the setApplicationContext method to inject applicationContext into @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext } @ RequestMapping (value = "/ pay/callback.do") public View callback (HttpServletRequest request) {if (paySuccess (request) {/ / construct payment success event PaySuccessEvent event = buildPaySuccessEvent (...); / / publish the event through applicationContext to achieve the purpose of notifying the observer this.applicationContext.publishEvent (event) } / * Voice broadcast processor * * / public class VoiceBroadcastHandler implements ApplicationListener {@ Override public void onApplicationEvent (PaySuccessEvent event) {/ / Voice broadcast Logic} / / other processors have similar logic
Conclusion: the observer model will be decoupled between the observer and the observer, and the existence of the observer will not affect the existing logic of the observer.
Decorator design pattern
Schema definition
The decorator is used to wrap the original class and make enhancements in the case of transparency to the user. For example, BufferedInputStream in Java can enhance its packaged InputStream to provide buffering.
Working with scen
When you want to enhance the functionality of the original class, but do not want to add too many subclasses, you can use the decorator mode to achieve the same effect.
Practical experience
The author was promoting the whole company to access the trace system, so I also provided some tools to solve the automatic weaving of trace and the automatic transfer of context.
In order to support context passing between threads, I added TraceRunnableWrapper as a decoration class, so that the context of the parent thread is passed through to the child thread, which is completely transparent to the user.
The code is as follows:
/ * * Runnable decorator that can automatically carry trace context * / public class TraceRunnableWrapper implements Runnable {/ / packaged target object private Runnable task; private Span parentSpan = null; public TraceRunnableWrapper (Runnable task) {/ / 1. Get the context of the current thread (because no thread switch has occurred during new, so you need to get the context here) / / anyone interested in this piece of code can see opentracing API io.opentracing.Scope currentScope = GlobalTracer.get (). ScopeManager (). Active (); / / 2. When saving the parent context parentSpan = currentScope.span (); this.task = task;} @ Override public void run () {/ / run, bind the context of the parent thread to the current thread io.opentracing.Scope scope = GlobalTracer.get (). ScopeManager (). Activate (parentSpan,false); task.run () }} / / user new Thread (new Runnable () {run (...)}). Replace start () with new TraceRunnableWrapper (new Runnable () {run (...)}) .start ()
Summary: the use of decorator mode to enhance the function, for users only need to do a simple combination to continue to use the original function.
Appearance design pattern
Schema definition
What is appearance is to provide a unified entrance to the outside world:
First, it can hide the internal details of the system.
Second, it can reduce the complexity of users.
For example, DispaterServlet in SpringMVC, all Controller are exposed uniformly through DispaterServlet.
Working with scen
Reduce the complexity of the user and simplify the access cost of the client.
Practical experience
My company provides some open capabilities to third-party ISV, such as equipment control, unified payment, statement download and so on.
Because they belong to different teams, the interfaces provided are different. In the initial stage, there are not many interfaces, and ISV can accept them, but later, when there are more interfaces, ISV begins to complain that the access cost is too high.
In order to solve this problem, we add a front-end controller GatewayController in front of the open interface, which is actually the embryonic form of our later open platform.
GatewayController uniformly exposes an interface gateway.do, which converges the request parameters and response parameters of the external interface in GatewayController. GatewayController also uses a unified interface when routing to the back-end service.
The comparison before and after the transformation is as follows:
The approximate code is as follows:
User: HttpClient.doPost ("/ gateway.do", "{'method':'trade.create','sign':'wxxaaa','timestamp':'15311111111'},' bizContent':' business parameter'") GatewayController: @ RequestMapping ("/ gateway.do") JSON gateway (HttpServletRequest req) {/ / 1. Assemble open request OpenRequest openRequest = buildOpenRequest (req); OpenResponse openResponse = null; / / 2. Request routing if ("trade.create" .equals (openRequest.getMethod () {/ / proxy to trade service by dubbo openResponse = TradeFacade.execute (genericParam);} else if ("iot.message.push" .equals (openRequest.getMethod ()) {/ / proxy to iot service by httpclient openResponse = HttpClient.doPost ('http://iot.service/generic/execute'genericParam);) } if (openResponse.isSuccess ()) {return {"code": "10000", "bizContent": openResponse.getResult ()};} else {"code": "20000", "bizCode": openResponse.getCode ()};}} "what is the implementation of the responsibility chain design pattern". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
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.