Backend Development 12 min read

Refactoring the Game Account Order Process with a Three‑Layer Interface and Strategy‑Template Pattern

This article describes how a game‑account order system with scattered core code and no design patterns was refactored into a clean three‑layer interface architecture using a strategy‑template approach, detailing the design, implementation, testing, gray‑release strategy, and post‑deployment safeguards.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Refactoring the Game Account Order Process with a Three‑Layer Interface and Strategy‑Template Pattern

Background

The original game‑account order flow had become a "code mountain" due to rapid iteration, with core logic scattered across multiple services, heavy use of if‑else statements, and poor readability, maintainability, and extensibility, which severely impacted delivery efficiency.

Problems identified

Core code distributed across many classes and services.

Lack of design patterns leading to tight coupling.

Testing and deployment required touching many branches, causing regressions.

Key questions were how to refactor the code, which design patterns to adopt, how to test and release the new flow, and how to handle incidents.

How to Refactor

After analyzing the seven order types (derived from two basic modes: customer‑service delivery and self‑delivery), the team chose a strategy‑template pattern combined with a three‑layer interface design. The three layers are:

First‑level interface: handles front‑end interactions, MQ processing, and calls from other services.

Second‑level interface: provides the invariant core capabilities (place order, pay, deliver, confirm receipt, etc.) with separate implementations for self‑delivery and customer‑service delivery.

Third‑level interface: contains special handling for each order type.

Interface Design

Below is the first‑level interface definition:

public interface IGameAccountOrderDealProcess {
    /** Process a placed but unpaid order */
    int handlePlaceOrder(GameAccountOrderContext orderContext) throws Exception;
    /** Process a successfully paid order */
    int handlePaySuccessOrder(GameAccountOrderContext orderContext) throws Exception;
    /** Process a delivered order */
    int handleDeliverOrder(GameAccountOrderContext orderContext) throws Exception;
    /** Process order cancelled before payment */
    int handleCancelBeforePayOrder(GameAccountOrderContext orderContext) throws Exception;
    /** Process order cancelled after payment */
    int handleCancelAfterPayOrder(GameAccountOrderContext orderContext) throws Exception;
    /** Process order after receipt confirmation */
    int handleConfirmReceiptOrder(GameAccountOrderContext orderContext) throws Exception;
T getOrderTradeData(String logStr, Long orderId, Integer device, Long uid);
    ZZOpenScfBaseResult
uploadAccountAndPwd(GameAccountSelfTrade.AccountPwdArg arg, long uid, String logStr, ServiceHeaderEntity header) throws Exception;
    boolean deliverOrder(GameAccountOrderContext orderContext) throws Exception;
    ZZOpenScfBaseResult
confirmReceiptOrder(GameAccountOrderContext orderContext, Long uid, boolean needRisk) throws Exception;
}

The third‑level interface for special order handling is defined as:

public interface ITradeSelfHandler {
    GameAccountTradeFlow.GameAccountTradeType getOrderTrade();
    // MQ related processing
    void fillExtraOrderInfoBeforeInsert(GameAccountOrderResultEntity orderEntity, GameAccountOrderContext orderContext);
    void handleAfterPlaceOrder(GameAccountOrderContext orderContext);
    void handleCancelBeforePay(GameAccountOrderContext orderContext);
    int handleCancelAfterPay(GameAccountOrderContext orderContext) throws Exception;
    int handleAfterPaySuccess(GameAccountOrderContext orderContext);
    int handleAfterConfirmReceipt(GameAccountOrderContext orderContext) throws Exception;
    Date getWithDrawlTime();
    void orderAlreadyPayPushMsgNew(GameAccountOrderContext orderContext, Pair
jumpUrl);
    List
getOrderSplitModelList(GameAccountOrderContext orderContext, OrderMaxSettleInfo settleInfo);
    void buildOrderSpiUiData(GameAccountOrderContext orderContext, GameOrderSpiConfig bConfig, GameOrderSpiConfig sConfig, SpiUiData spiUiData) throws Exception;
    void otherOperationAfterReceipt(GameAccountOrderContext orderContext, Long uid);
}

Concrete Implementation

All core order code was consolidated into a single service and exposed via RPC.

Related classes and utilities were moved into a common package for easier navigation.

Naming conventions, single‑responsibility principle, and clear context objects were enforced.

Example of the order context entity:

public class GameAccountOrderContext {
    private String logStr;
    private Long orderId;
    private Integer mqStatus;
    private Order order;
    private GameAccountOrderResultEntity accountOrderEntity;
    private AccountOrderStatusEnum orderStatus;
    private Boolean hasInsuranceService; // whether the order has insurance
    private GameAccountTradeFlow.GameAccountTradeType tradeType;
    private GameAccountProductData accountProductData;
    private ZZProduct product;
    private ZZProductExt productExt;
    private Map
extValueMap;
    private AccountHelpSaleClue helpSaleClue; // help‑sale clue
    private DistributionShareInfoDTO distributionShareInfo; // distribution info
    private ITradeSelfHandler tradeSelfHandler;
    private Integer serviceUiStatus; // order SPI status
}

Deployment Assurance

To minimize risk, the team enforced strict offline testing, ensured that the new flow behaved identically to the old one, and adopted a gray‑release strategy based on order type and daily volume. Gray configuration example:

[
  {
    "orderType": 6,
    "dayNum": 50,
    "isTotalGray": true
  }
]

The method isNewOrderProcess decides whether an order should follow the new flow, consulting the gray configuration, Redis flags, and runtime checks.

An alert mechanism was added to critical nodes (account upload, delivery, withdrawal) to send enterprise‑WeChat notifications, allowing immediate rollback of the gray release if needed.

Summary

After refactoring, adding or modifying an order type only requires implementing or updating the corresponding handler class, without affecting other types, greatly improving development efficiency and code quality while providing a robust testing and release pipeline.

design patternsJavastrategy patternbackend architecturerefactoringTemplate Method
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.