Forced to refactor the code, I killed if else this time

Time:2021-10-15

This article is included in the personal blog:www.chengxy-nds.topTechnology, resource sharing and progress together

Recently, the company seems to have been financed! I began to look for channels to promote like crazy. Now I finally understand why I was recruiting people in a big way. It turned out that I was playing a big game, which was a good thing for employees on the whole. Maybe it’s time to raise the topic of salary increase with the boss.

However, the salary rise has not yet come down, followed by the demand for one car, new channels are accessed every day, and each channel must provide personalized support, with a sharp increase in development. I don’t have much time to be more polite recently. It’s a luxury to get off work on time!

Forced to refactor the code, I killed if else this time

Due to the proliferation of promotion channels, each order source does special logic processing when placing an order. Maybe one source will be added every two days, which has changed the previous order logic. For long-term consideration, I decided to reconstruct the existing logic. After all, long pain is better than short pain.

Traditional implementation

Let’s look at the pseudo code below, which is roughly the code of single logic before reconstruction. Because there are few sources, it’s easy to do itif-elseLogical judgment is sufficient to meet the needs.

At present, the processing logic of each order source has hundreds of lines of code. It looks bloated, but I’m stunned that I haven’t started to reconstruct. On the one hand, the business side always makes you hurry up like a ghost and wants to quickly realize the requirements. This is the fastest way to write; On the other hand, I dare not move and face itantiqueLevel code, still want to be safe.

But this time, dozens of sources have been added at once, and it is impossible to maintain them in this way. Imagine that bloatedif-elseCode, not to mention development, think big!

public class OrderServiceImpl implements IOrderService {

Implementation of policy pattern

Think about whether it is more appropriate to reconstruct based on the current business scenario or to use the policy modeoopOne of the more famous design patterns in is the abstraction of method behavior.

The policy pattern defines a family of algorithms with common behavior. Each algorithm is encapsulated, can be replaced with each other, and changes independently of the client.

1、 Usage scenario of policy mode:

  • There are many ways to deal with the same problem, only when there are differences in specific behaviors;
  • When it is necessary to safely encapsulate multiple operations of the same type;
  • The same abstract class has multiple subclasses, which the client needs to useif-elseperhapsswitch-caseTo select a specific subclass.

This is the modified code in the policy mode:

@Component

Each order source has its own logical implementation class. Each time you need to add an order source, you can directly create an implementation class and modify it@OrderHandlerType(16)You don’t have to turn over the smelly and long ones anymoreif-lese

Moreover, when assigning tasks, each person is responsible for developing several order source logics, which can not interfere with each other, and reduce the conflict of merging codes to a great extent.

2、 Specific implementation process:

1. Define annotation

Define an annotation that identifies the source of the order@OrderHandlerType

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderHandlerType {
    int value() default 0;
}

2. Abstract service processor

Abstract up a specific business processor

public abstract class AbstractHandler {
    abstract public void handle(OrderBO orderBO);
}

3. Project start scanhandlerentrance

@Component

4. Tool classes required for scanning

public class ClassScaner {

5. Instantiate abstract classes based on types

@Component
public class HandlerContext {

    @Autowired
    private ApplicationContext beanFactory;

    public  AbstractHandler getInstance(Integer type){

        Map<Integer,Class> map = (Map<Integer, Class>) beanFactory.getBean(OrderHandlerType.class.getName());

        return (AbstractHandler)beanFactory.getBean(map.get(type));
    }

}

6. Call entry

When I receive an MQ message, I process multiple order source businesses, and different order sources are routed to different business processing classes.

@Component
@RabbitListener(queues = "OrderPipelineQueue")
public class PipelineSubscribe{

    private final Logger LOGGER = LoggerFactory.getLogger(PipelineSubscribe.class);

    @Autowired
    private HandlerContext HandlerContext;

    @Autowired
    private OrderValidateService orderValidateService;

    @RabbitHandler
    public void subscribeMessage(MessageBean bean){

        OrderBO orderBO = JSONObject.parseObject(bean.getOrderBO(), OrderBO.class);

        if(null != orderBO &&CollectionUtils.isNotEmpty(bean.getType()))
        {
            for(int value:bean.getType())
            {
                AbstractHandler handler = HandlerContext.getInstance(value);
                handler.handle(orderBO);
            }
        }
    }
}

Receiving entityMessageBeanClass code

public class MessageBean implements Serializable {
    private static final long serialVersionUID = 5454831432308782668L;
    private String cachKey;
    private List<Integer> type;
    private String orderBO;

    public MessageBean(List<Integer> type, String orderBO) {
        this.type = type;
        this.orderBO = orderBO;
    }
}

The above design patterns and methods seem a little complicated, and some small partners question: “what are you doing for aif-else, isn’t it troublesome to make such trouble, custom annotations and so many classes? ” Some small partners are obsessed with performance problems, and the performance of the policy mode may be worse than that of the policy modeif-else

But I think it’s worth adding a little complexity and sacrificing performance to change the cleanliness and maintainability of the code. However, one person has one idea. How to choose depends on the specific business scenario!

Forced to refactor the code, I killed if else this time

Advantages and disadvantages of policy mode

advantage

  • It is easy to expand. To add a new policy, you only need to add a specific policy class. There is basically no need to change the original code, which conforms to the open and closed principle
    • Avoid using multiple conditional selection statements, fully reflect the object-oriented design idea, and the policy classes can switch freely. Since the policy classes all implement the same interface, they can switch freely
    • Each policy class uses a policy class, which conforms to the principle of single responsibility. The client is decoupled from the policy algorithm. Both rely on the abstract policy interface and comply with the principle of dependency inversion
    • The client does not need to know which policy classes are available, which conforms to the principle of minimum knowledge

shortcoming

  • Policy mode. When there are too many policy algorithms, many policy classes will be created
  • The client does not know which policy classes there are and cannot decide which policy class to use. This can be solved by encapsulating the common public package or by makingIOC containerandDependency injectionTo solve the problem.

The following is a part of the order source policy class. I have to say that there are many policy classes.

Forced to refactor the code, I killed if else this time

summary

Everything has two sides,if-elseMulti tier nesting and also have their own advantages and disadvantages:

  • if-elseThe advantage is that it is simple. If you want to quickly iterate functions, there is less logical nesting and will not continue to increase,if-elseBetter, the disadvantages are obvious, the code is cumbersome and inconvenient to maintain.

  • Strategy modeSeparate the logic of each scenario for maintenance. The same abstract class has multiple subclasses and needs to be usedif-elseperhapsswitch-caseWhen selecting specific subclasses, it is recommended to select the policy mode. Its disadvantage is that there will be more policy class files.

The two implementation methods have their own advantages and disadvantages. How to choose them depends on the specific business scenario, or the saying that the design pattern is not used for use, but must be used in the most appropriate position.

gossip

Usually chatting with fans in private, many people feel about learning design patterns: they recite a lot of design patterns, but usually development is not written all dayif-elseBusiness logic is not used at all.

It’s not impossible to learn design patterns, but sometimes there are no suitable scenarios. For business scenarios like the one we’re talking about today, design patterns can be used to solve them perfectly.

It is a common thing that you can work without using more than n technologies. There will be many considerations when using one technology for a stable project. Will the new technology increase the complexity of the system? What are its performance bottlenecks? These must be taken into account. After all, project stability is the most important, and no one dare to take risks easily.

We learn technology not only for whether it will be used in the current project, but also for technology accumulation and long-term planning. People can go high without some ability.


Original is not easy, burning hair output content, I hope you can have a lost harvest!

Hundreds of various technical e-books were sorted out and sent to our friends. Official account reply [666] collect by oneself. We have set up a technical exchange group with some partners to discuss technology and share technical materials with a view to learning and progress together. If you are interested, scan the code and join us!

Forced to refactor the code, I killed if else this time

This work adoptsCC agreement, reprint must indicate the author and the link to this article

Recommended Today

Swift advanced (XV) extension

The extension in swift is somewhat similar to the category in OC Extension can beenumeration、structural morphology、class、agreementAdd new features□ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc What extensions can’t do:□ original functions cannot be overwritten□ you cannot add storage attributes or add attribute observers to existing attributes□ cannot add parent […]