Practice of Design Mode in Meituan Takeaway Marketing Business

Posted by siesmith on Fri, 20 Mar 2020 09:20:17 +0100

1. Preface

With the continuous iteration and development of Meituan take-out business, the number of take-out users is also growing at a high speed.In this process, take-out marketing plays a "mainstay" role, because the rapid growth of users cannot be separated from efficient marketing strategies.Because of the changing market and business environment, marketing strategies are often complex and changeable. As a support department of marketing business, marketing technical teams need to respond quickly and efficiently to the changes in demand brought by the changes in marketing strategies.Therefore, the design and implementation of a marketing system that is easy to expand and maintain is the goal and essential work of the delegation take-out marketing technical team.

This article describes how design patterns can help us build a scalable and maintainable marketing system from top to bottom.This paper first introduces the relationship between design patterns and Domain-Driven Design (hereinafter referred to as DDD), then describes the design patterns used in the introduction of take-out marketing business and their specific practice cases.

2. Design Patterns and Domain-Driven Design

To design a marketing system, we usually deconstruct our business from the top down, for which we introduced DDD.Strategically speaking, DDD can guide us through the analysis from problem space to solution, mapping business needs into domain context and mapping relationships between contexts.Tactically, DDD can refine the domain context and form an effective and detailed domain model to guide engineering practice.One of the key implications of building a domain model is to ensure that the expanding and changing needs evolve and develop within the domain model without corruption of the model and overflow of domain logic.For the practice of DDD, you can refer to the previous "Meituan technical team launched the" Practice of Domain-driven Design in Internet Business Development "Article.

At the same time, we need to implement and implement domain models in code engineering.Because code engineering is an intuitive representation of domain model in engineering practice, it is also a direct representation of domain model at the technical level.The design mode can be said to be a bridge between domain model and code project, which can effectively solve the transformation from domain model to code project.

Why do design patterns naturally serve as a bridge between domain models and code engineering?In fact, Eric Evans, author of the 2003 Domain Driven Design book, explains this in his first book.He believes that different positions affect how people view what is a "pattern".Therefore, whether it is domain-driven or design mode, it is essentially a "mode", only to solve different problems.From the standpoint of business modeling, the DDD model solves how to model a domain.From the standpoint of code practice, design mode focuses on the design and implementation of code.Since they are all patterns in nature, they naturally have some similarities.

The so-called "pattern" is a set of methodologies that have been repeatedly used or validated.From an abstract or more macro point of view, patterns should be applied in both DDD and design patterns as long as they conform to the usage scenario and solve practical problems.In fact, Evans does the same.In his book, he explains how two traditional GOF design patterns, Strategy and Composite, solve domain model building.Therefore, when domain models need to be translated into code engineering, isomorphic patterns naturally translate domain models into code models.

3. Specific Cases of Design Mode in Takeaway Marketing Business

3.1 Why design patterns are needed

Characteristics of Marketing Business

As mentioned earlier, the difference between marketing business and other relatively stable business models, such as transactions, is that marketing needs will be adjusted with the changing market, users and environment.It is for this reason that the takeout marketing technical team chose DDD for domain modeling and used design patterns to practice and reflect domain models at the level of code engineering in applicable scenarios.This enables healthy evolution of domain and code models while supporting business changes and avoiding model corruption.

Understanding design patterns

Software Design pattern, also known as Design pattern, is a set of experience summary of repeated use, known to most people, categorized and coded design.Design patterns are used to reuse code, make it easier for others to understand, ensure code reliability, and program reuse.It can be understood as: "There are no design patterns in the world. More people are using them, so a set of design patterns has been summarized."

Design Mode Principles

There are seven basic principles of object-oriented design patterns:

  • Open Closed Principle (OCP)
  • Single Responsibility Principle (SRP)
  • Liskov Substitution Principle (LSP)
  • Dependency Inversion Principle (DIP)
  • Interface Segregation Principle (ISP)
  • Composite/Aggregate Reuse Principle (CARP)
  • Least Knowledge Principle (LKP) or Law of Demeter (LOD)

The simple understanding is that the Open and Close Principle is the general outline, which guides us to be open to expansion and close to modification; the Single Responsibility Principle guides us to achieve a single class responsibility; the Richter Replacement Principle guides us not to destroy the inheritance system; the Relying on the Inverted Principle guides us to be Interface-oriented programming; the Interface Isolation Principle guides us to be simple when designing interfaces; DimittThe rule guides us to reduce coupling.

The design pattern is to guide us how to make a good design through these seven principles.However, the design mode is not a set of "fantastic" and it is a set of methodologies, a high cohesion, low coupling design ideas.On this basis, we can freely play, or even design our own set of design models.

Of course, learning design mode or practicing design mode in engineering must go deep into a specific business scene, combined with the understanding of business scene and domain model building, in order to understand the essence of design mode thought.It is extremely empty to learn from specific business logic or to use design patterns.Next, we'll explore how design patterns can be used to implement reusable, easy-to-maintain code through take-out marketing practices.

3.2 Practice of Design Patterns in Invitation to Order Business

3.2.1 Business Profile

Invite Orders is a reward platform for delegate takeaway users to invite other users to place orders.That is, User A invites User B, and User B gives User A a certain cash reward (hereinafter referred to as the reward) after placing an order in Meituan.At the same time, in order to coordinate the relationship between cost and benefit, there are several calculation strategies for reward return.Invitation to order background mainly involves two technical points:

  1. The calculation of return bonus amounts involves different calculation rules.
  2. The whole process from invitation to reward return.

3.2.2 Reward Rules and Design Mode Practice

Business Modeling

The diagram is a business logic view of the reward return rule calculation:

The rules for calculating the return bonus amount can be seen in this business logic diagram.The first step is to determine if the user meets the reward return criteria based on the user's status.If the reward return criteria are met, continue to judge whether the current user belongs to a new or an old user, thus giving different reward schemes.There are several different incentive schemes involved:

new user

  • General reward (fixed amount reward)
  • Gradient Awards (The more people you invite, the more rewards you give depending on the number of people you invite)

Old Users

  • Return bonus is calculated based on the user attributes of older users.In order to evaluate the effect of different invitations, there are many reward mechanisms for old users.

After calculating the reward amount, you also need to update the user's bonus information and notify the settlement service to settle the user's amount.The two modules are the same for all rewards.

You can see that no matter what kind of user, the reward return process is unchanged, the only change is the reward return rule.Here, we can refer to the open and close principle to keep the reward return process closed and open to possible extended reward return rules.We abstract the reward return rules as reward strategies, that is, different reward return schemes for different types of users are treated as different reward strategies, different reward return strategies will produce different reward results.

In our domain model, reward strategy is a value object. We produce reward strategy value objects for different users through factory approach.Below we will describe the engineering implementation of the above domain model, that is, the practical application of the factory mode and the strategy mode.

Mode: Factory Mode

The factory mode is subdivided into the factory method mode and the abstract factory mode. This paper mainly introduces the factory method mode.

Schema Definition: Defines an interface for creating objects, allowing subclasses to decide which class to instantiate.Factory methods delay the instantiation of a class until its subclasses.

The generic class diagram for factory mode is as follows:

We explain how to use the factory mode through a more general piece of code:

//Abstract products
public abstract class Product {
    public abstract void method();
}
//Define a specific product (you can define multiple specific products)
class ProductA extends Product {
    @Override
    public void method() {}  //Specific execution logic
}
//Abstract factory
abstract class Factory<T> {
    abstract Product createProduct(Class<T> c);
}
//Specific factories can produce appropriate products
class FactoryA extends Factory{
    @Override
    Product createProduct(Class c) {
        Product product = (Product) Class.forName(c.getName()).newInstance();
        return product;
    }
}

Mode: Policy Mode

Pattern Definition: Defines a series of algorithms, encapsulates each one, and they are interchangeable.A policy pattern is an object behavior pattern.

The general class diagram for the policy pattern is as follows:

We explain how to use policy patterns through a more general piece of code:

//Define a policy interface
public interface Strategy {
    void strategyImplementation();
}
​
//Specific policy implementations (multiple specific policy implementations can be defined)
public class StrategyA implements Strategy{
    @Override
    public void strategyImplementation() {
        System.out.println("Executing Policy A");
    }
}
​
//Encapsulation strategies to block direct access to strategies and algorithms by high-level modules and possible policy changes
public class Context {
    private Strategy strategy = null;
​
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
  
    public void doStrategy() {
        strategy.strategyImplementation();
    }
}

​ engineering practice

From the reward business model described above, we can see that the main process of reward returning is to select different reward returning strategies, each reward returning strategy includes three steps: calculating the reward amount, updating the user reward information, and settling the account.We can use the factory mode to produce different strategies and the strategy mode to implement different strategies.First, determine that we need to generate n different reward strategies, coded as follows:

//Abstract Policy
public abstract class RewardStrategy {
    public abstract void reward(long userId);
  
    public void insertRewardAndSettlement(long userId, int reward) {} ; //Update user information and Settlements
}
//New user reward specific strategy A
public class newUserRewardStrategyA extends RewardStrategy {
    @Override
    public void reward(long userId) {}  //Specific calculation logic,...
}
​
//Specific Reward Policy for Old Users A
public class OldUserRewardStrategyA extends RewardStrategy {
    @Override
    public void reward(long userId) {}  //Specific calculation logic,...
}
​
//Abstract factory
public abstract class StrategyFactory<T> {
    abstract RewardStrategy createStrategy(Class<T> c);
}
​
//Specific factory creation strategies
public class FactorRewardStrategyFactory extends StrategyFactory {
    @Override
    RewardStrategy createStrategy(Class c) {
        RewardStrategy product = null;
        try {
            product = (RewardStrategy) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {}
        return product;
    }
}

After you have produced a specific strategy through the factory model, it is easy to think of using the strategy model to execute our strategy based on our previous introduction.The code is as follows:

public class RewardContext {
    private RewardStrategy strategy;
​
    public RewardContext(RewardStrategy strategy) {
        this.strategy = strategy;
    }
​
    public void doStrategy(long userId) { 
        int rewardMoney = strategy.reward(userId);
        insertRewardAndSettlement(long userId, int reward) {
          insertReward(userId, rewardMoney);
          settlement(userId);
       }  
    }
}

Next we combine the factory model with the strategy model to complete the reward return process:

public class InviteRewardImpl {
    //Reward Main Course
    public void sendReward(long userId) {
        FactorRewardStrategyFactory strategyFactory = new FactorRewardStrategyFactory();  //Create a factory
        Invitee invitee = getInviteeByUserId(userId);  //Query user information based on user id
        if (invitee.userType == UserTypeEnum.NEW_USER) {  //New User Reward Strategy
            NewUserBasicReward newUserBasicReward = (NewUserBasicReward) strategyFactory.createStrategy(NewUserBasicReward.class);
            RewardContext rewardContext = new RewardContext(newUserBasicReward);
            rewardContext.doStrategy(userId); //Execute reward-back strategy
        }if(invitee.userType == UserTypeEnum.OLD_USER){}  //Old User Reward Strategy,... 
    }
}

The factory method pattern helps us directly produce a specific policy object, and the policy pattern helps us to ensure that these policy objects can be switched freely without changing other logic for decoupling purposes.Through the combination of these two modes, when we need to add a reward-back strategy to our system, we just need to implement the RewardStrategy interface without considering other changes.When we need to change the policy, simply modify the class name of the policy.Not only enhances the scalability of the system, avoids a lot of conditional judgments, but also achieves the purpose of high cohesion and low coupling in a real sense.

3.2.3 Reward Process and Design Mode Practice

Business Modeling

When the invitee accepts the invitation of the inviter and orders, the reward return background receives the record of the invitee's order, at this time the inviter also enters the reward return process.First we subscribe to the user order message and check the reward rules for the order.For example, whether to place an order using a red envelope, whether to place an order within the validity period of the red envelope, whether the order meets certain preferential amounts, and so on.When these conditions are met, we place the order information in a delayed queue for subsequent processing.The delay message is processed after T+N days to determine whether the user has refunded the order and, if not, the user has been rewarded.If the reward return fails, there is also a reward compensation process in the background, and reward will be returned again.Its flow is shown in the following figure:

We do domain modeling for these business processes:

  1. After receiving the order message, the user enters the pending verification state;
  2. After verification, if the verification passes, the user enters the pre-reward status and places in the delayed queue.If the check fails, the user enters the non-reward status and ends the process;
  3. After T+N days, process the delay message and enter the status of reward pending if the user does not refund.If the user refunds, enter the failure state and end the process;
  4. Execute the reward, if the reward is successful, enter the completion state, and end the process.If the reward return is unsuccessful, it enters the status of pending compensation;
  5. Users in the compensated state will trigger the compensation mechanism periodically by the task until the reward is successful, enter the completed state, and guarantee the end of the process.

As you can see, through modeling, we map the multiple steps of the reward return process to the state of the system.For describing the state of the system, the common concept used in DDD is domain events, and practical scenarios for event tracing are also mentioned.Of course, in design mode, there is also a code model that can describe the state of the system, that is, state mode.In the invitation order system, our main process is reward.For rewards, the actions and actions to be performed in each state are different.Therefore, using the state mode can help us unify the management and expansion of the system state and the flow between states.

Mode: State mode

Schema Definition: Allows an object to change its behavior when its internal state changes, and the object appears to have changed its class.

The generic class diagram for the state pattern is shown below:

Comparing the types of policy patterns, you will find that they are similar to the class diagram of the state pattern, but there is actually a big difference, reflected in the concrete class.Policy mode acts on code by contexts to produce the only ConcreteStrategy, while state mode implements business logic by contexts organizing multiple ConcreteState s to form a state transition diagram.Next, we explain how to use the state mode through a common piece of code:

//Define an abstract state class
public abstract class State {
    Context context;
    public void setContext(Context context) {
        this.context = context;
    }
    public abstract void handle1();
    public abstract void handle2();
}
//Define State A
public class ConcreteStateA extends State {
    @Override
    public void handle1() {}  //What must be handled in this state
​
    @Override
    public void handle2() {
        super.context.setCurrentState(Context.contreteStateB);  //Switch to State B        
        super.context.handle2();  //Execute tasks in state B
    }
}
//Define State B
public class ConcreteStateB extends State {
    @Override
    public void handle2() {}  //Things that must be dealt with in this state,...
  
    @Override
    public void handle1() {
        super.context.setCurrentState(Context.contreteStateA);  //Switch to State A
        super.context.handle1();  //Perform tasks in state A
    }
}
//Define a context management environment
public class Context {
    public final static ConcreteStateA contreteStateA = new ConcreteStateA();
    public final static ConcreteStateB contreteStateB = new ConcreteStateB();
​
    private State CurrentState;
    public State getCurrentState() {return CurrentState;}
​
    public void setCurrentState(State currentState) {
        this.CurrentState = currentState;
        this.CurrentState.setContext(this);
    }
​
    public void handle1() {this.CurrentState.handle1();}
    public void handle2() {this.CurrentState.handle2();}
}
//Define client execution
public class client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setCurrentState(new ContreteStateA());
        context.handle1();
        context.handle2();
    }
}

engineering practice

From the previous introduction to state modes, we can see that when the transition between States is not very complex, there are a lot of state-independent actions in common state modes, resulting in a lot of useless code.In our practice, downstream of a state does not involve much state swapping, so we simplify the state mode.The current state is only responsible for what the current state is about to handle, and the flow of state is the responsibility of a third class.The code of practice is as follows:

//Context for reward status execution
public class RewardStateContext {
​
    private RewardState rewardState;
  
    public void setRewardState(RewardState currentState) {this.rewardState = currentState;}
    public RewardState getRewardState() {return rewardState;}
    public void echo(RewardStateContext context, Request request) {
        rewardState.doReward(context, request);
    }
}
​
public abstract class RewardState {
    abstract void doReward(RewardStateContext context, Request request);
}
​
//Pending Verification Status
public class OrderCheckState extends RewardState {
    @Override
    public void doReward(RewardStateContext context, Request request) {
        orderCheck(context, request);  //Verify incoming orders, determine whether vouchers are used, whether preferential conditions are met, etc.
    }
}
​
//Status to be compensated
public class CompensateRewardState extends RewardState {
    @Override
    public void doReward(RewardStateContext context, Request request) {
        compensateReward(context, request);  //Return failed, reward compensation is required for users
    }
}
​
//Return status, Return status, Success status, Failure status (omitted logically here)
//..
​
public class InviteRewardServiceImpl {
    public boolean sendRewardForInvtee(long userId, long orderId) {
        Request request = new Request(userId, orderId);
        RewardStateContext rewardContext = new RewardStateContext();
        rewardContext.setRewardState(new OrderCheckState());
        rewardContext.echo(rewardContext, request);  //Start reward, order validation
        //if-else logic here is just a state transition process, not actual business logic
        if (rewardContext.isResultFlag()) {  //Enter pre-reward status if order validation is successful
            rewardContext.setRewardState(new BeforeRewardCheckState());
            rewardContext.echo(rewardContext, request);
        } else {//If the order verification fails, enter the reward return failure process,...
            rewardContext.setRewardState(new RewardFailedState());
            rewardContext.echo(rewardContext, request);
            return false;
        }
        if (rewardContext.isResultFlag()) {//The pre-reward check is successful, enter the reward waiting process,...
            rewardContext.setRewardState(new SendRewardState());
            rewardContext.echo(rewardContext, request);
        } else {  //If the pre-reward check fails, enter the reward failure process,...
            rewardContext.setRewardState(new RewardFailedState());
            rewardContext.echo(rewardContext, request);
            return false;
        }
        if (rewardContext.isResultFlag()) {  //Return successful, enter the reward return end process,...
            rewardContext.setRewardState(new RewardSuccessState());
            rewardContext.echo(rewardContext, request);
        } else {  //Return failure, reward compensation phase,...
            rewardContext.setRewardState(new CompensateRewardState());
            rewardContext.echo(rewardContext, request);
        }
        if (rewardContext.isResultFlag()) {  //Compensation succeeded, entering the reward completion stage,...
            rewardContext.setRewardState(new RewardSuccessState());
            rewardContext.echo(rewardContext, request);
        } else {  //Compensation fails and remains in the current state until compensation succeeds (or artificial intervention after multiple compensation failures)
            rewardContext.setRewardState(new CompensateRewardState());
            rewardContext.echo(rewardContext, request);
        }
        return true;
    }
}

The core of state mode is encapsulation, which encapsulates state and state transition logic into classes, and also reflects the "open and close" and "single responsibility" principles.Each state is a subclass, and whether it is modified or added, only one subclass needs to be modified or added.In our application scenarios, the number of States and state transitions are much more complex than the above examples, and our logic becomes clearer by avoiding a lot of if-else code through State Mode.At the same time, due to the good encapsulation of state patterns and the design principles followed, we can manage each state in a complex business scenario with ease.

3.3 Comment on the Practice of Design Mode in Takeaway Delivery System

3.3.1 Business Profile

Continuing with the example, App Reviews will reserve more than one resource slot for marketing use, showing users some more delicious takeaway foods, in order to increase their intention to order takeaway.When the user clicks on the "Meituan Takeaway" entry on the first page of the review, the resource bits begin to load and the appropriate display Banner will be filtered out through some rules.

3.3.2 Design Mode Practice

Business Modeling

For the launch business, it is to show the resources that match the current user in these resource bits.Its flow is shown in the following figure:

From the process, we can see that first the operators will configure the resources to be displayed and the rules to filter the resources.Our resources have relatively flexible filtering rules, which are reflected in three points:

  1. Most of the filtering rules are reusable, but they can also be extended and changed.
  2. The filtering rules and order are different for different resource bits.
  3. The same resource location may have different filtering rules due to different stages of the business.

The filtering rules themselves are value objects, and we use them to complete the filtering logic of the resource bits in the way of domain services.The following diagram describes the process by which resource bits are filtered for rules related to user characteristics:

In order to decouple the filtering rules, close the modifications to individual rule value objects, and open the filtering chain composed of rule collections, we introduced the responsibility chain model in the domain service of resource bit filtering.

Model: Responsibility Chain Model

Schema Definition: Enables multiple objects to process requests, thereby avoiding coupling between the sender and recipient of the request.Join these objects into a chain and pass the request along the chain until an object handles it.

The general class diagram for the responsibility chain model is as follows:

We explain how to use the chain of responsibility pattern through a more general piece of code:

//Define an abstract handle
public abstract class Handler {
    private Handler nextHandler;  //Point to Next Processor
    private int level;  //Levels that a processor can handle
​
    public Handler(int level) {
        this.level = level;
    }
​
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
​
    // Handle request delivery, note final, subclasses are not overridden
    public final void handleMessage(Request request) {
        if (level == request.getRequstLevel()) {
            this.echo(request);
        } else {
            if (this.nextHandler != null) {
                this.nextHandler.handleMessage(request);
            } else {
                System.out.println("Already at the end");
            }
        }
    }
    // Abstract method, subclass implementation
    public abstract void echo(Request request);
}
​
// Define a specific handleA
public class HandleRuleA extends Handler {
    public HandleRuleA(int level) {
        super(level);
    }
    @Override
    public void echo(Request request) {
        System.out.println("I am Processor 1,I'm working on it A rule");
    }
}
​
//Define a specific handleB
public class HandleRuleB extends Handler {}  //...
​
//Client implementation
class Client {
    public static void main(String[] args) {
        HandleRuleA handleRuleA = new HandleRuleA(1);
        HandleRuleB handleRuleB = new HandleRuleB(2);
        handleRuleA.setNextHandler(handleRuleB);  //This is the point. String handleA and handleB together
        handleRuleA.echo(new Request());
    }
}

​ engineering practice

The following code shows you how to implement this set of processes:

//Define an abstract rule
public abstract class BasicRule<CORE_ITEM, T extends RuleContext<CORE_ITEM>>{
    //There are two methods, evaluate to determine whether a rule has been executed or execute to execute specific rule content.
    public abstract boolean evaluate(T context);
    public abstract void execute(T context) {
}
​
//Define all rule implementations
//Rule 1: Judging service availability
public class ServiceAvailableRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {
    @Override
    public boolean evaluate(UserPortraitRuleContext context) {
        TakeawayUserPortraitBasicInfo basicInfo = context.getBasicInfo();
        if (basicInfo.isServiceFail()) {
              return false;
        }
        return true;
    }
  
    @Override
    public void execute(UserPortraitRuleContext context) {}
​
}
//Rule 2: Determine if the current user property meets the user property requirements for the current resource bit placement
public class UserGroupRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {
    @Override
    public boolean evaluate(UserPortraitRuleContext context) {}
  
    @Override
    public void execute(UserPortraitRuleContext context) {
        UserPortrait userPortraitPO = context.getData();
        if(userPortraitPO.getUserGroup() == context.getBasicInfo().getUserGroup().code) {
          context.setValid(true);
        } else {
          context.setValid(false);
        }
    }
}
  
//Rule 3: Determine if the current user is dropping a city, omit the logic
public class CityInfoRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {}
//Rule 4: Filter resources based on user activity, omitted logically
public class UserPortraitRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {} 
​
//We string these rules together by spring to form a request chain
    <bean name="serviceAvailableRule" class="com.dianping.takeaway.ServiceAvailableRule"/>
    <bean name="userGroupValidRule" class="com.dianping.takeaway.UserGroupRule"/>
    <bean name="cityInfoValidRule" class="com.dianping.takeaway.CityInfoRule"/>
    <bean name="userPortraitRule" class="com.dianping.takeaway.UserPortraitRule"/>
      
    <util:list id="userPortraitRuleChain" value-type="com.dianping.takeaway.Rule">
        <ref bean="serviceAvailableRule"/>
        <ref bean="userGroupValidRule"/>
        <ref bean="cityInfoValidRule"/>
        <ref bean="userPortraitRule"/>
    </util:list>
      
//Rule Execution
public class DefaultRuleEngine{
    @Autowired
    List<BasicRule> userPortraitRuleChain;
​
    public void invokeAll(RuleContext ruleContext) {
        for(Rule rule : userPortraitRuleChain) {
            rule.evaluate(ruleContext)
        }
    }
}

The most important advantage of the responsibility chain model is decoupling, separating the client from the handler. The client does not need to know which handler handles the event, nor does the handler need to know the entire process.In our system, background filtering rules change frequently, and there may also be a transitive relationship between rules and rules. Through the responsibility chain model, we separate rules from rules and inject the transitive relationship between rules and rules into the List through Spring to form a chain relationship.When you add a rule, you only need to implement the BasicRule interface, then add the new rule to Spring in order.When deleting, you only need to delete the relevant rules, no other logic of the code needs to be considered.This significantly improves the flexibility of the code, improves the efficiency of code development, and ensures the stability of the system.

4. Summary

Starting from the marketing business, this paper introduces the transformation from domain model to code engineering, introduces the design mode from DDD, and details the four modes of factory method mode, strategy mode, responsibility chain mode and status mode in the marketing business.In addition to these four modes, proxy mode, singleton mode, adapter mode, and so on, are heavily used in our code engineering. For example, adapter mode is used in our implementation of DDD antiseptic layer, which shields business logic from interaction with third-party services.No more elaboration due to length.

For marketing business, changing business strategy leads to changing demand is the main problem we are facing.How to cope with complex and ever-changing needs is what we must consider when refining domain models and implementing code models.DDD and design patterns provide a relatively complete set of methodologies to help us complete domain modeling and engineering implementations.In fact, design patterns are like mirrors, mapping domain models to code models, effectively improving code reuse, scalability, and system maintainability.

Of course, design mode is only a summary of many years'experience in the field of software development. Any simple or complex design mode will follow the above seven design principles. As long as you truly understand the seven design principles, design mode should not be a difficult task for us.However, using design patterns does not require us to follow the rules. As long as our code model design follows these seven principles, we will find that a design pattern has already been used in our original design.

5. References

6. Introduction of Authors

Wu Liangliang joined Meituan Takeaway in 2017 as a team development engineer in the background of Meituan Takeaway marketing.

Recruitment Information

Meituan Takeaway Shanghai R&D Center has long been recruiting front-end, data warehouse, machine learning/data mining algorithm engineers. All interested students are welcome to send their resumes to: tech@meituan.com (Headline note: Meituan Takeaway-Shanghai)

Topics: Spring Programming