This week’s work was to reconstruct a refund requirement.

background

I am in charge of the order module of an e-commerce app, because with the continuous development of business, there are various order types.

Order dimension

For example, there are ordinary orders, group purchase orders, combination orders, service card service orders and other orders

Different orders have different refund logic

For example, when refunding ordinary orders, it is necessary to refund to the C-terminal user, modify the order status, and check whether there is free running fee

Then, the free running fee is calculated differently due to different payment modes.

For example, a payment is calculated based on a percentage of the order amount. The upper limit is 5RMB

Second stage payment, according to the type of order, fixed deduction of 10RMB is like this

The user dimensions

What do you mean?

Is not the user, the logic of refund is not the same.

For example, if you are a VIP user, your refund can be refunded immediately, for example, the third-party platform pays you in advance.

If you are a regular user, it may take up to 2 business days to get a refund.

You have used taobao’s refund, should be clear. After you reach a certain level, your refund is paid to you by Taobao in advance, not by the merchant. After the merchant really confirms the refund, the merchant gives the money to Taobao.

Here, we need to combine the user dimension with the order dimension.

The refund logic used to be written for ordinary orders. Let’s say it was written by A RD

Later, group purchase orders were added, at which point a new refund logic was added. Let’s say it was written by B RD

Later, combined orders were added, and a new refund logic was added. C RD, for example

Later later… You know…

Because each RD understands different logic, and the deadline is tight, it is easy to cause more and more confusion in the code

The code must be refactored at this point.

Design scheme

After understanding the basic logic of the business, we need to combine the user dimension and order dimension for consideration

I had the strategic model in mind.

Now I analyze it from the order dimension

Why the strategic model?

Because each order has a different payment method, it leads to different refund logic. The strategy mode is applicable to:

  • 1. If there are many classes in a system that are distinguished only by their behavior, the use of the policy pattern dynamically allows an object to choose one behavior among many.
  • A system needs to dynamically choose one of several algorithms.
  • 3. If an object has many behaviors, these behaviors can be implemented using multiple conditional selection statements without appropriate patterns. If… Else is complex and difficult to maintain)

In human words: the same behavior, there are different ways of expression.

Does that sound a little bit polymorphic to you?

Why template mode?

As I delve deeper into the refund business, SOME of the logic is common.

For example: order verification, update the refund form, calculation of idle running fees

At this point, the template pattern can be used to solve the problem.

The template mode applies to the following scenarios:

  • 1. Multiple subclasses share the same methods and logic.
  • 2. Important, complex methods can be considered as template methods.

Finally, I used the factory mode, which I could use or not, but was optimized.

Use it as a container: an instance of the load policy pattern

The code field

First, let’s start with the refund entry:

The strategy pattern
Public void refund(OrderInfo refundVO) throws Exception {try {// checkOrderInfo(refundVO); / / assembly refund table entity data, library prepareDataAndInsertDataToDB (refundVO); Use different refund strategies for different users --> Policy mode IRefundUserStrategy refundUserStrategy = RefundUserStrategyFactory.getRefundUserStrategy(key); refundUserStrategy.doRefundByUser(); }catch (Exception e){log.error("C end user refund error :",e); }}Copy the code

Main logic:

  • Order validation
  • Assemble the physical data of the refund form and drop it off
  • Use different refund strategies for different users

Next, we focused on: RefundUserStrategyFactory

/ * * * user refund policy - factory factory pattern * / public class RefundUserStrategyFactory {private static final HashMap < UserLevelEnum, IRefundUserStrategy> refudUserStrategyFactory = new HashMap<>(); public static IRefundUserStrategy getRefundUserStrategy(UserLevelEnum userLevelEnum) { return refudUserStrategyFactory.get(userLevelEnum); } public static void putQueryStrategy(UserLevelEnum userLevelEnum, IRefundUserStrategy userStrategy) { refudUserStrategyFactory.put(userLevelEnum, userStrategy); }}Copy the code

In plain English, the factory here is essentially a HashMap collection container.

In fact, there are two main methods, let me abstract: is reading and writing two methods.

read

Timing: reading is to the RefundUserStrategyFactory. GetRefundUserStrategy (key). Read it when you use it.

write

So when do you put it in?

After the object is initialized, of course, this time you need to incorporate the @postConstruct annotation into Spring

Here’s an example:

Template pattern
@Component @Slf4j public class NormalUserRefundStrategy implements IRefundUserStrategy { @PostConstruct private void initStrategy() { RefundUserStrategyFactory.putQueryStrategy(UserLevelEnum.NORMAL,this); } / / the refund of the average user logic doRefundByUser () {/ / / / omit a pile of code calls a different order refund policy interface AbstractOrderRefundTemplate orderRefundTemplate = orderRefundComp.getOrderRefundTemplate(key); / / here, according to a template to refund policy for different order - > template pattern orderRefundTemplate. ExeOrderRefund (); }}Copy the code

After what we did up there. The logic of the code will be particularly clear:

  • Order validation
  • Update refund Form
  • Different refund strategies are adopted according to different users
    • Depending on the order strategy

conclusion

Later, when you add a new order type, you only need to add a specific policy class. In line with the open and close principle.

That’s the way to do it

Factory mode + Policy mode + template mode

To optimize code that is logically messed up.

In general, if you see a lot of if-else in your code logic, you can use this strategy directly.

If you have similar application design patterns to optimize code issues, please leave a comment.

Finally, I wish you a happy May Day traffic jam hahaha hahaha hahaha!!