In Web development, we often use fields in database tables as “tags” to represent multiple “states”, such as:

We take the online shopping process of some treasure as an example for analysis. In the order table, the ZT field is used to indicate the status of the order. Common states are:

Status code State that
0 For the payment
1 To send the goods
2 For the goods
3 To evaluate
4 after-sales

When we want to query various types of orders according to the conditions, only need an interface, in the front of the corresponding status code can be passed. In the DAO layer, the following statements are used to query:

select * from orders where zt = #{zt}
Copy the code

How to have high scalability?

Suppose there are several “requirements that are not requirements” :

  1. I want the order to be sorted by the time the order shipped or is expected to arrive, and the rest by the time the order was created
  2. I want to separate the status of “goods to be received” into two states: “user did not receive the goods” and “user received the goods but did not click the button to confirm receipt of the goods”

What’s the conventional way?

  • Requirement 1 (different states have different processing methods) :

    This is easy, add a judgment in the sevice layer can be done, the rest of the code does not change, code is as follows:

// 2 indicates goods to be received
if(zt == 2) {// Order by demand, order by shipping time or expected delivery time
}else{
  // All orders in other states are sorted according to the order creation time
}
Copy the code

This code is small enough to change, but what if I wanted to sort all the orders in different states in different ways? You might write the following code

if(zt==0) {// Order processing code to be paid...
}else if(zt==1){
  
}else if(zt==2){
  
}else if(zt==3){
  
}else if(zt==4){
  
}
Copy the code

The above code is too low, some friends may use switch to optimize (I won’t write the code here, because there is no difference).

  • Requirement 2 (add a new state representation) :

    It’s easy to just add a new state to the if-else or switch code above.

Think about how to kill if-else?

The above method can fulfill our requirements, but it has the following shortcomings:

1. Faced with "all kinds of strange requirements", we had to change the above code frequently, and over time, it would become a mess. We don't even want to look at the code anymore; 2. If we add a new state representation to the zT field, we have to add if-else. This is too complicated.Copy the code

Use policy patterns to solve if-else problems

Yes, using the policy pattern is a good way to solve the problem of doing too much state judging code. For example, each of the above if-else code is split into a class or method for processing.

I’m not going to write the main code, because I’m going to do the main thing, but the only way I’m going to do this is if else, decouple the code to a certain extent. But it doesn’t really solve the if-else problem, and it’s the most common solution on the web.

If you don’t know much about strategy patterns, check out this article, and you’ll see how it works below. The way to learn strategic patterns

Try using Spring to work with the policy pattern

One of the principles of programming, “open for extension, closed for modification,” defines an interface class for querying a list of orders in different states. As follows:

public interface OrderService {

    /** * Query the order list in the corresponding state *@param zt
     * @return* /
    List<Order> getOrderList(String zt);
}
Copy the code

Then create different implementation classes based on different order states. For example, the order query class “to be paid” looks like this:

Although the following naming is an example of a mistake, it is well understood

@Service("orderServiceDfk") // This name is really unfriendly, but I'm sure you can understand
public class PendingParymentOrderSeviceImpl implements OrderService {
    /** * Query the list of orders to be paid **@param zt
     * @return* /
    @Override
    public List<Order> getOrderList(String zt) {
      // Use the DAO layer to query the order list from the database
      return null;
    }
Copy the code

The zT value is different from the zT value in the front end, and the zT value is different from the zT value in the back end, but we can remove the if-else completely through Spring.

Our Controller layer code is as follows:

@RestController
public class OrderController {
  private String orderServiceBeanNamePrefix = "orderService";

  @RequestMapping("getOrderList/{zt}")
  public List<Order> getOrderList(@PathVariable("zt") String zt) {

    // Get the corresponding processing state of the bean to process
    If-else (); // If else ()
    OrderService orderService = (OrderService) SpingContext.getBean(orderServiceBeanNamePrefix + zt);
    List<Order> orderList = orderService.getOrderList();

    returnorderList; }}Copy the code

We used a utility class to get the bean from the Spring container. The code is as follows:

Spring will automatically call the setApplicationContext method. Spring will automatically call the setApplicationContext method. Spring will automatically call the setApplicationContext method. Passing in the Spring container context * we'll save the Spring context here * *@date 2020/5/18
 * @auther Lyn4ever
 */
@Component
public class SpingContext implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /** * Get bean * from Spring container according to name@param name
     * @return* /
    public static Object getBean(String name){
        return applicationContext.getBean(name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("I saved the Spring context"); applicationContext = applicationContext; }}Copy the code

Conclusion:

The solution to if-else is to use the policy pattern and use different classes to handle the logic for different “states” of orders, so that it can be “decoupled” nicely. However, if we add a “state representation”, we add if-else to the main logic to determine which class to use.

There are many ways to solve the if-else problem: Abstract factories are a good way to do this. The same problem can be solved by using Spring inversion of control. The benefits of this are as follows:

  1. “Real” addresses if-else irrelevant to our business;
  2. There is no need for the front and back end to state “agreed”, before 0 means “to be paid”, 1 means “to be shipped” such an operation, if you remember wrong, there will be a big problem. It is now represented by a specific string, meaning that the front end passes in the bean that it wants to solve the solution to, eliminating the “complex and error-prone convention” part.

Code Address:

Feel good, you can follow my wechat public number oh

Follow the wechat official account “Small Fish and Java” to get more learning content