Applying Design Patterns and Domain‑Driven Design in Meituan Takeaway Marketing System
The Meituan Takeaway Marketing team shows how combining domain‑driven design with classic patterns such as Factory Method, Strategy, State and Responsibility Chain creates an extensible, maintainable reward system that adapts to rapidly changing business rules while keeping the domain model clean and SOLID‑compliant.
Business strategy changes frequently, leading to volatile requirements—a common challenge for many technology teams. This article, authored by the Meituan Takeaway Marketing technical team, explains how to design an extensible and maintainable marketing system by bridging domain‑driven design (DDD) and software design patterns.
1. Introduction
As Meituan Takeaway grows, its marketing component becomes a critical pillar. Rapidly changing market and business conditions make marketing strategies complex and mutable. The engineering team therefore needs a system that can quickly adapt while keeping the domain model clean.
2. Design Patterns and Domain‑Driven Design
DDD helps translate business problems into a domain model, mapping requirements to bounded contexts and relationships. Design patterns act as a bridge from the domain model to concrete code, providing reusable solutions for common architectural problems.
3. Concrete Pattern Cases in the Marketing System
3.1 Why Design Patterns Are Needed
Marketing requirements evolve constantly; DDD alone cannot express the varying reward calculation rules. By encapsulating each rule as a strategy, the system stays open for extension while remaining closed for modification (Open‑Closed Principle).
3.2 Factory Method Pattern
Factory Method isolates object creation, allowing new reward strategies to be added without touching existing code. The following Java snippet shows a generic factory implementation:
public abstract class Product { public abstract void method(); }
public class ProductA extends Product { @Override public void method() { /* concrete logic */ } }
public abstract class Factory<T> { public abstract Product createProduct(Class<T> c); }
public class FactoryA extends Factory { @Override public Product createProduct(Class c) { return (Product) Class.forName(c.getName()).newInstance(); } }3.3 Strategy Pattern
Strategy encapsulates interchangeable algorithms. In the reward system, each reward rule (e.g., fixed amount, tiered reward) is a concrete strategy.
public interface Strategy { void strategyImplementation(); }
public class StrategyA implements Strategy { @Override public void strategyImplementation() { System.out.println("Executing Strategy A"); } }
public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void doStrategy() { strategy.strategyImplementation(); } }3.4 State Pattern
The reward process consists of several states (order check, pre‑reward, pending reward, success, failure, compensation). The State pattern models these states as objects, allowing transitions without large if‑else blocks.
public abstract class State { Context context; public abstract void handle1(); public abstract void handle2(); }
public class ConcreteStateA extends State { @Override public void handle1() { /* ... */ } @Override public void handle2() { context.setCurrentState(ConcreteStateB); context.handle2(); } }
public class Context { private State currentState; public void setCurrentState(State s) { currentState = s; currentState.setContext(this); } public void handle1() { currentState.handle1(); } public void handle2() { currentState.handle2(); } }3.5 Responsibility Chain Pattern
Filtering rules for resource placement are modeled as a chain of handlers, each deciding whether to process the request or pass it downstream.
public abstract class Handler { private Handler next; private int level; public Handler(int level) { this.level = level; } public final void handleMessage(Request r) { if (level == r.getRequestLevel()) { echo(r); } else if (next != null) { next.handleMessage(r); } else { System.out.println("Reached end of chain"); } } public abstract void echo(Request r); }4. Engineering Practice
All reward strategies are created by a StrategyFactory. The RewardContext holds a strategy and executes it. The overall flow is:
Receive order message → OrderCheckState validates the order.
If valid, transition to BeforeRewardCheckState (pre‑reward).
Execute the appropriate RewardStrategy (new‑user or old‑user).
Update user reward info and trigger settlement.
If settlement fails, move to CompensateRewardState and retry until success.
By combining Factory Method and Strategy, adding a new reward rule only requires implementing a new RewardStrategy and registering it with the factory.
5. Summary
The article demonstrates how DDD and four classic design patterns—Factory Method, Strategy, State, and Responsibility Chain—are applied to a real‑world marketing system. It also mentions the use of other patterns (Proxy, Singleton, Adapter) in the broader codebase.
Design patterns serve as a bridge between domain models and code, improving reusability, extensibility, and maintainability while adhering to the seven SOLID principles.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
