Practice of design mode in takeout marketing business

Posted by john8m on Fri, 28 Jan 2022 05:21:12 +0100

1, Foreword

With the continuous iteration and development of meituan takeout business, the number of takeout users is also growing at a high speed. In this process, takeout marketing plays a "mainstay" role, because the rapid growth of users is inseparable from efficient marketing strategies. Due to the changeable market environment and business environment, the marketing strategy is often complex and changeable. As the supporting department of marketing business, the marketing technology team needs to quickly and efficiently respond to the demand changes caused by the change of marketing strategy. Therefore, designing and implementing a marketing system that is easy to expand and maintain is the goal and required basic skill of meituan takeout marketing technology team.

Through the top-down way, this paper introduces how the design pattern helps us build a set of marketing system that is easy to expand and maintain. This paper will first introduce the relationship between design patterns and Domain Driven Design (hereinafter referred to as DDD), and then describe the design patterns used in the introduction of takeout marketing business and its specific practical cases.

2, Design patterns and Domain Driven Design

When designing a marketing system, we usually adopt a top-down approach to deconstruct the business. Therefore, we introduce DDD. At the strategic level, DDD can guide us to complete the analysis from problem space to solution, and map business requirements into domain context and the mapping relationship between contexts. From the tactical level, DDD can refine the domain context and form an effective and detailed domain model to guide engineering practice. A key significance of establishing a domain model is to ensure that the constantly expanding and changing requirements evolve and develop within the domain model without model corruption and domain logic overflow. For the practice of DDD, you can refer to the previously launched by meituan technical team< Practice of Domain Driven Design in Internet business development >A penny.

At the same time, we also need to implement and implement the domain model in code engineering. Because code engineering is not only the intuitive embodiment of domain model in engineering practice, but also the direct expression of domain model at the technical level. Design pattern can be said to be a bridge between domain model and code engineering. It can effectively solve the transformation from domain model to code engineering.

Why do design patterns naturally serve as a bridge between domain models and code engineering? In fact, Eric Evans, the author of Domain Driven Design Published in 2003, has given an explanation in this pioneering work. He believes that different positions will affect how people view what is a "model". Therefore, both domain driven patterns and design patterns are essentially "patterns", but they solve different problems. From the standpoint of business modeling, DDD model solves how to conduct domain modeling. From the standpoint of code practice, design patterns mainly focus on the design and implementation of code. Since they are all patterns in nature, they naturally have something in common.

The so-called "model" is a set of methodology that has been used or verified repeatedly. From an abstract or more macro point of view, as long as it conforms to the use scenario and can solve practical problems, patterns should be applied not only in DDD, but also in design patterns. In fact, Evans did the same. In his book, he explained how Strategy and Composite, two traditional GOF design patterns, solve the construction of domain model. Therefore, when the domain model needs to be transformed into code engineering, the isomorphic model can naturally translate the domain model into code model.

3, Specific cases of design mode in takeout marketing business

3.1 why design patterns are needed

Characteristics of marketing business

As mentioned above, the difference between marketing business and other businesses with relatively stable modes such as trading is that marketing needs will be adjusted with the continuous changes of market, users and environment. Therefore, the takeout marketing technical team chose DDD for domain modeling, and practiced and reflected the domain model at the level of code engineering with design patterns in applicable scenarios. In this way, while supporting business changes, we can make the domain and code model evolve healthily and avoid model corruption.

Understanding design patterns

Software Design pattern, also known as Design pattern, is a summary of code design experience that is repeatedly used, known by most people, classified and catalogued. The purpose of using Design pattern is to reuse the code, make the code easier to be understood by others, ensure the reliability of the code and the reusability of the program. It can be understood as: "there is no Design pattern in the world. When more people use it, they summarize a set of design patterns."

Design pattern principle

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

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

The simple understanding is: the opening and closing principle is the general program, which guides us to open to expansion and close to modification; The principle of single responsibility guides us to realize the single responsibility of class; The principle of Richter substitution guides us not to destroy the inheritance system; The principle of dependency inversion guides us to interface oriented programming; The principle of interface isolation guides us to simplify and single when designing interfaces; Dimitri's law directs us to reduce coupling.

Design pattern is to guide us how to make a good design through these seven principles. However, design pattern is not a set of "tricks", it is a set of methodology, a design idea of high cohesion and low coupling. On this basis, we can play freely and even design our own set of design patterns.

Of course, learning design patterns or practicing design patterns in engineering must go deep into a specific business scenario, combined with the understanding of business scenarios and the establishment of domain models, in order to realize the essence of design patterns. It is extremely empty to learn or use design patterns without specific business logic. Next, we will discuss how to use design patterns to realize reusable and easy to maintain code through the practice of takeout marketing business.

3.2 practice of design mode in "invite order" business

3.2.1 business introduction

"Invite to place an order" is A platform for meituan takeout users to invite other users to place an order and give rewards. That is, user A invites user B, and after user B places an order in meituan, user A will be given A certain cash reward (hereinafter referred to as reward). At the same time, in order to coordinate the relationship between cost and benefit, there will be multiple calculation strategies for reward. The background of inviting orders mainly involves two technical points:

  1. The calculation of the reward amount involves different calculation rules.
  2. The whole process from invitation to reward.

3.2.2 reward return rules and design mode Practice

Business modeling

The figure below is the business logic view of the reward return rule calculation:

From this business logic diagram, you can see the rules for calculating the bonus amount. First, determine whether the user meets the reward return conditions according to the user status. If the reward conditions are met, continue to judge whether the current user belongs to a new user or an old user, so as to give different reward schemes. There are several different reward schemes involved:

new user

  • Ordinary reward (give a fixed amount of reward)
  • Gradient Award (different reward amount will be given according to the number of people invited by users. The more people invited, the more reward amount)

Old users

  • Calculate the reward amount according to the user attributes of old users. In order to evaluate different effects of inviting new users, there are various 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. These two modules are the same for all rewards.

It can be seen that no matter what kind of user, the overall reward return process remains unchanged, and the only change is the reward return rules. Here, we can refer to the opening and closing principle to keep the reward return process closed and open the reward return rules that may be extended. We abstract the reward rules as reward strategies, that is, for different reward schemes of different user types, we regard them as different reward strategies, and different reward strategies will produce different reward amount results.

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

Mode: factory mode

Factory pattern is subdivided into factory method pattern and abstract factory pattern. This paper mainly introduces factory method pattern.

Schema definition: define an interface for creating objects, and let subclasses decide which class to instantiate. A factory method is a class whose instantiation is deferred to its subclasses.

The general class diagram of factory mode is as follows:

We explain how to use the factory mode through a relatively general code:

//Abstract products
public abstract class Product {
    public abstract void method();
}
//Define a specific product (multiple specific products can be defined)
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 corresponding 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: define a series of algorithms, encapsulate each algorithm, and they can be interchanged. Policy pattern is an object behavior pattern.

The general class diagram of policy mode is as follows:

We explain how to use the policy pattern through a relatively general code:

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

Engineering practice

Through the reward business model introduced above, we can see that the main process of reward is the process of selecting different reward strategies. Each reward strategy includes three steps: reward amount calculation, updating user bonus information and settlement. We can use factory mode to produce different strategies, and use policy mode to execute different strategies at the same time. Firstly, we need to generate n different reward strategies, which are coded as follows:

//Abstract strategy
public abstract class RewardStrategy {
    public abstract void reward(long userId);
  
    public void insertRewardAndSettlement(long userId, int reward) {} ; //Update user information and settlement
}
//Specific strategy for new user reward A
public class newUserRewardStrategyA extends RewardStrategy {
    @Override
    public void reward(long userId) {}  //Specific calculation logic
}
​
//Specific strategy of reward 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);
}
​
//Create specific policies for specific factories
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 the specific strategy is produced through the factory mode, according to our previous introduction, it is easy to think of using the policy mode to implement our strategy. The specific codes are 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 mode and strategy mode to complete the whole reward return process:

public class InviteRewardImpl {
    //Reward return process
    public void sendReward(long userId) {
        FactorRewardStrategyFactory strategyFactory = new FactorRewardStrategyFactory();  //Create factory
        Invitee invitee = getInviteeByUserId(userId);  //Query user information according to user id
        if (invitee.userType == UserTypeEnum.NEW_USER) {  //Reward strategy for new users
            NewUserBasicReward newUserBasicReward = (NewUserBasicReward) strategyFactory.createStrategy(NewUserBasicReward.class);
            RewardContext rewardContext = new RewardContext(newUserBasicReward);
            rewardContext.doStrategy(userId); //Implement reward return strategy
        }if(invitee.userType == UserTypeEnum.OLD_USER){}  //Old user reward strategy 
    }
}

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

3.2.3 reward return process and design mode Practice

Business modeling

When the invitee accepts the invitation from the invitee and places an order, the reward return background receives the invitee's order record, and the invitee also enters the reward return process. First, we subscribe to the user's order message and verify the reward return rules of the order. For example, whether to place an order with a red envelope, whether to place an order within the validity period of the red envelope, and whether the order meets a certain preferential amount. When these conditions are met, we put the order information into the delay queue for subsequent processing. After T+N days, process the delay message to judge whether the user has refunded the order. If not, the user will be rewarded. If the reward fails, there is a reward compensation process in the background, and the reward will be returned again. The process is shown in the figure below:

We conduct domain modeling for the above business processes:

  1. After receiving the order message, the user enters the status to be verified;
  2. After verification, if the verification passes, the user enters the pre reward status and is placed in the delay queue. If the verification fails, the user enters the status of no reward return and ends the process;
  3. After T+N days, the delay message will be processed. If the user does not refund, it will enter the status of pending reward return. If the user refunds, it will enter the failed state and end the process;
  4. Execute the reward return. If the reward return is successful, enter the completion state and end the process. If the reward is not successful, enter the state to be compensated;
  5. Users in the status to be compensated will trigger the compensation mechanism regularly by the task until the reward is returned successfully, enter the completion status and the guarantee process ends.

It can be seen that we map multiple steps of the reward process to the state of the system through modeling. For the expression of system state, the concept commonly used in DDD is domain event. In addition, the practice scheme of event traceability is also mentioned. Of course, in the design pattern, there is also a code model that can express the system state, that is, the state pattern. In the invitation and order system, our main process is reward. For reward, the actions and operations to be carried out in each state are different. Therefore, the use of state mode can help us to uniformly manage and expand the system state and the flow between states.

Mode: status mode

Schema definition: when an object's internal state changes, it is allowed to change its behavior. The object looks like it has changed its class.

The general class diagram of state mode is shown in the following figure:

Comparing the types of policy patterns, you will find that they are very similar to the class diagram of state patterns, but there are actually great differences, which are embodied in concrete class. The policy mode generates the only ConcreteStrategy through the context and acts on the code, while the state mode organizes multiple concretestates through the context to form a state transition diagram to realize the business logic. Next, let's explain how to use state mode through a general 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 status A
public class ConcreteStateA extends State {
    @Override
    public void handle1() {}  //Things that must be handled in this state
​
    @Override
    public void handle2() {
        super.context.setCurrentState(Context.contreteStateB);  //Switch to state B        
        super.context.handle2();  //Perform tasks in status B
    }
}
//Define status B
public class ConcreteStateB extends State {
    @Override
    public void handle2() {}  //Things that must be handled in this state
  
    @Override
    public void handle1() {
        super.context.setCurrentState(Context.contreteStateA);  //Switch to state A
        super.context.handle1();  //Perform tasks in status 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

Through the introduction of state mode, we can see that when the transition between States is not very complex, there are a large number of state independent actions in the general state mode, resulting in a large number of useless code. In our practice, the downstream of a state does not involve too many state changes, so we simplify the state mode. The current status is only responsible for the things to be handled in the current status, and the flow of status is the responsibility of the third party. The practical code is as follows:

//Context of 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);
}
​
//Status to be verified
public class OrderCheckState extends RewardState {
    @Override
    public void doReward(RewardStateContext context, Request request) {
        orderCheck(context, request);  //Check the incoming orders to determine whether coupons 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);  //If the reward return fails, the user needs to be compensated for the reward return
    }
}
​
//Pre reward status, to be reward status, success status, failure status (logic omitted 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 return and order verification
        //The if else logic here is only to express the state transformation process, not the actual business logic
        if (rewardContext.isResultFlag()) {  //If the order is verified successfully, it will enter the pre reward status
            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, and 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()) {  //If the reward is successful, enter the reward ending process
            rewardContext.setRewardState(new RewardSuccessState());
            rewardContext.echo(rewardContext, request);
        } else {  //If the reward return fails, enter the reward return compensation stage
            rewardContext.setRewardState(new CompensateRewardState());
            rewardContext.echo(rewardContext, request);
        }
        if (rewardContext.isResultFlag()) {  //Compensation is successful, enter the reward return completion stage
            rewardContext.setRewardState(new RewardSuccessState());
            rewardContext.echo(rewardContext, request);
        } else {  //If the compensation fails, it will remain in the current state until the compensation succeeds (or manual intervention after multiple compensation failures)
            rewardContext.setRewardState(new CompensateRewardState());
            rewardContext.echo(rewardContext, request);
        }
        return true;
    }
}

The core of the state pattern is encapsulation, which encapsulates the state and state transition logic into the interior of the class, and also well reflects the "opening and closing principle" and "single responsibility principle". Each state is a subclass. No matter modifying or adding a state, you only need to modify or add a subclass. In our application scenario, the number of States and state transitions are much more complex than the above examples. A large number of if else codes are avoided through "state mode", which makes our logic clearer. At the same time, due to the good encapsulation of the state mode and the design principles followed, we can easily manage various states in complex business scenarios.

3.3 comment on the practice of design mode in takeout delivery system

3.3.1 business introduction

For example, multiple resource slots will be reserved in the takeout channel of the comment App for marketing to show users some more exquisite and delicious takeout foods in order to increase users' intention to order takeout. When the user clicks the "meituan takeout" entry on the comment home page, the resource bit starts to load, and the appropriate display Banner will be selected through some rules.

3.3.2 design mode Practice

Business modeling

For business launch, it is necessary to display the resources that meet the current user in these resource bits. The process is shown in the figure below:

From the process, we can see that firstly, operators will configure the resources to be displayed and the rules for filtering resources. The filtering rules of our resources are relatively flexible, which are reflected in three points:

  1. Most of the filtering rules are reusable, but they will also be expanded and changed.
  2. The filtering rules and order of different resource bits are different.
  3. For the same resource bit, the filtering rules may be different due to different stages of the business.

Filtering rules are value objects. We operate these rule value objects through domain services to complete the filtering logic of resource bits. The following figure describes the process of filtering rules related to user characteristics in the resource bit:

In order to realize the decoupling of filtering rules, close the modification of a single rule value object and open the filtering chain composed of rule sets, we introduce the responsibility chain model into the domain service of resource bit filtering.

Mode: responsibility chain mode

Schema definition: multiple objects have the opportunity to process the request, thus avoiding the coupling relationship between the sender and receiver of the request. Connect these objects into a chain and pass the request along the chain until an object processes it.

The general class diagram of responsibility chain mode is as follows:

We explain how to use the responsibility chain model through a relatively general code:

//Define an abstract handle
public abstract class Handler {
    private Handler nextHandler;  //Point to next processor
    private int level;  //The level that the processor can handle
​
    public Handler(int level) {
        this.level = level;
    }
​
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }
​
    // Handle request delivery. Note that final and subclasses cannot be 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("It's 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'm handler 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);  //That's the point. String handleA and handleB together
        handleRuleA.echo(new Request());
    }
}

Engineering practice

Let's show you how to realize this set of process through code:

//Define an abstract rule
public abstract class BasicRule<CORE_ITEM, T extends RuleContext<CORE_ITEM>>{
    //There are two methods. evaluate is used to judge whether the rule has been executed, and execute is used to execute the specific rule content.
    public abstract boolean evaluate(T context);
    public abstract void execute(T context) {
}
​
//Define the specific implementation of all rules
//Rule 1: judge 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: judge whether the current user attribute meets the user attribute requirements of the current resource bit
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: judge whether the current user is in the delivery City, and the specific logic is omitted
public class CityInfoRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {}
//Rule 4: filter resources according to the user's activity, and the specific logic is omitted
public class UserPortraitRule extends BasicRule<UserPortrait, UserPortraitRuleContext> {} 
​
//We string these rules through 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, which separates the client from the handler. The client does not need to know which handler handles the event, and the handler does not need to know the whole process of processing. In our system, the background filtering rules will change frequently, and there may be a transmission relationship between rules. Through the responsibility chain mode, we separate rules from rules, and inject the transmission relationship between rules into the List through Spring to form a chain relationship. When adding a rule, you only need to implement the BasicRule interface, and then add the new rules to Spring in order. When deleting, you only need to delete the relevant rules without considering other logic of the code. Thus significantly improve the flexibility of the code, improve the development efficiency of the code, and ensure the stability of the system.

4, Summary

Starting from the marketing business, this paper introduces the transformation from domain model to code engineering, leads to the design mode from DDD, and introduces in detail the specific implementation of factory method mode, strategy mode, responsibility chain mode and state mode in the marketing business. In addition to these four modes, proxy mode, singleton mode and adapter mode are also widely used in our code engineering. For example, we use adapter mode in the implementation of DDD anti-corrosion coating, which shields the interaction between business logic and third-party services. Due to space reasons, I will not elaborate too much.

For the marketing business, the main problem we face is that the changeable business strategy leads to the changeable demand. How to deal with complex and changeable requirements is what we must consider when refining the domain model and implementing the code model. DDD and design patterns provide a relatively complete set of methodology to help us complete domain modeling and engineering implementation. In fact, the design pattern is like a mirror, which maps the domain model into the code model, effectively improves the reusability and scalability of the code, and also improves the maintainability of the system.

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

5, References