返利软件架构设计:多平台适配的抽象工厂模式实践

返利软件架构设计:多平台适配的抽象工厂模式实践

大家好,我是省赚客APP研发者阿可!省赚客APP(juwatech.cn)需同时对接淘宝联盟、京东联盟、拼多多开放平台等多个电商返利渠道。各平台在商品解析、佣金查询、订单回调等接口上存在显著差异,若采用硬编码分支判断,将导致代码高度耦合、难以维护。为此,我们基于抽象工厂模式设计了一套统一的多平台适配架构,实现"一次调用,多端兼容"。本文将结合核心接口定义与具体实现,详解该模式在返利系统中的落地。

抽象产品接口定义

首先定义各平台共有的能力契约:

java 复制代码
package juwatech.cn.platform;

public interface ProductParser {
    ParsedProduct parse(String input);
}

public interface CommissionCalculator {
    BigDecimal calculateCommission(String itemId, Long userId);
}

public interface CallbackVerifier {
    boolean verify(Map<String, String> params, String signature);
}

public interface PlatformClient {
    String getPlatformCode();
    ProductParser getProductParser();
    CommissionCalculator getCommissionCalculator();
    CallbackVerifier getCallbackVerifier();
}

其中 ParsedProduct 为标准化商品模型:

java 复制代码
public class ParsedProduct {
    private String platform;
    private String itemId;
    private String title;
    private BigDecimal price;
    private String shopName;
    // getters/setters
}

抽象工厂基类与注册机制

定义抽象工厂基类,并通过 Spring 自动注册所有实现:

java 复制代码
package juwatech.cn.platform.factory;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public abstract class AbstractPlatformFactory implements InitializingBean {

    private static final Map<String, PlatformClient> CLIENT_REGISTRY = new ConcurrentHashMap<>();

    public static PlatformClient getClient(String platformCode) {
        PlatformClient client = CLIENT_REGISTRY.get(platformCode);
        if (client == null) {
            throw new IllegalArgumentException("Unsupported platform: " + platformCode);
        }
        return client;
    }

    @Override
    public void afterPropertiesSet() {
        PlatformClient client = createClient();
        CLIENT_REGISTRY.put(client.getPlatformCode(), client);
    }

    protected abstract PlatformClient createClient();
}

淘宝联盟具体工厂实现

以淘宝为例,实现其专属工厂:

java 复制代码
package juwatech.cn.platform.taobao;

@Component
public class TaobaoPlatformFactory extends AbstractPlatformFactory {

    @Autowired
    private TaobaoApiClient taobaoApiClient;

    @Override
    protected PlatformClient createClient() {
        return new TaobaoPlatformClient(taobaoApiClient);
    }
}

class TaobaoPlatformClient implements PlatformClient {
    private final TaobaoApiClient apiClient;

    public TaobaoPlatformClient(TaobaoApiClient apiClient) {
        this.apiClient = apiClient;
    }

    @Override
    public String getPlatformCode() {
        return "TAOBAO";
    }

    @Override
    public ProductParser getProductParser() {
        return new TaobaoProductParser(apiClient);
    }

    @Override
    public CommissionCalculator getCommissionCalculator() {
        return new TaobaoCommissionCalculator(apiClient);
    }

    @Override
    public CallbackVerifier getCallbackVerifier() {
        return new TaobaoCallbackVerifier();
    }
}

具体解析器实现:

java 复制代码
class TaobaoProductParser implements ProductParser {
    private final TaobaoApiClient client;

    public TaobaoProductParser(TaobaoApiClient client) {
        this.client = client;
    }

    @Override
    public ParsedProduct parse(String input) {
        String itemId = TaobaoUrlUtils.extractItemId(input);
        TaobaoItem item = client.getItemInfo(itemId);
        return new ParsedProduct()
            .setPlatform("TAOBAO")
            .setItemId(item.getNumIid())
            .setTitle(item.getTitle())
            .setPrice(new BigDecimal(item.getZkFinalPrice()))
            .setShopName(item.getNick());
    }
}

拼多多工厂实现(对比展示差异)

java 复制代码
@Component
public class PddPlatformFactory extends AbstractPlatformFactory {
    @Override
    protected PlatformClient createClient() {
        return new PddPlatformClient(new PddOpenApiClient());
    }
}

class PddPlatformClient implements PlatformClient {
    private final PddOpenApiClient client;

    public PddPlatformClient(PddOpenApiClient client) {
        this.client = client;
    }

    @Override
    public String getPlatformCode() { return "PDD"; }

    @Override
    public ProductParser getProductParser() {
        return input -> {
            String goodsId = PddUrlUtils.extractGoodsId(input);
            PddGoods goods = client.getGoodsDetail(goodsId);
            return new ParsedProduct()
                .setPlatform("PDD")
                .setItemId(goods.getGoodsId())
                .setTitle(goods.getGoodsName())
                .setPrice(goods.getMinGroupPrice().divide(BigDecimal.valueOf(100)))
                .setShopName(goods.getMallName());
        };
    }

    @Override
    public CommissionCalculator getCommissionCalculator() {
        return (itemId, userId) -> {
            // 拼多多佣金需根据用户身份和活动动态计算
            return client.queryCommissionRate(itemId, userId);
        };
    }

    @Override
    public CallbackVerifier getCallbackVerifier() {
        return (params, sign) -> PddSignUtil.verify(params, appSecret, sign);
    }
}

统一服务入口调用

业务层无需感知平台细节,仅需传入平台标识:

java 复制代码
@Service
public class UnifiedCommissionService {

    public void processCallback(String platform, Map<String, String> params, String sign) {
        PlatformClient client = AbstractPlatformFactory.getClient(platform);
        
        if (!client.getCallbackVerifier().verify(params, sign)) {
            throw new SecurityException("Invalid signature for platform: " + platform);
        }

        String tradeId = params.get("trade_id");
        String itemId = params.get("item_id");
        Long userId = Long.valueOf(params.get("user_id"));

        BigDecimal commission = client.getCommissionCalculator().calculateCommission(itemId, userId);
        accountService.credit(userId, commission, "返利入账");

        commissionRecordMapper.insert(tradeId, itemId, userId, commission, platform);
    }

    public ParsedProduct parseProduct(String platform, String input) {
        PlatformClient client = AbstractPlatformFactory.getClient(platform);
        return client.getProductParser().parse(input);
    }
}

扩展性与测试优势

新增平台(如京东)只需:

  1. 实现 JdPlatformFactory;
  2. 注入所需 API 客户端;
  3. 无需修改任何现有业务逻辑。

单元测试可轻松 Mock 特定平台 Client:

java 复制代码
@Test
void testTaobaoParse() {
    PlatformClient mockClient = mock(PlatformClient.class);
    when(mockClient.getProductParser()).thenReturn(input -> new ParsedProduct().setTitle("测试商品"));
    
    // 替换注册表(测试专用)
    AbstractPlatformFactory.CLIENT_REGISTRY.put("TAOBAO", mockClient);
    
    ParsedProduct result = service.parseProduct("TAOBAO", "https://...");
    assertEquals("测试商品", result.getTitle());
}

本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!

相关推荐
蜗牛一步步往上爬13 分钟前
第十六章 C++语言在深度学习中的应用
开发语言·c++·深度学习
这个昵称不容易2 小时前
SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在
java·springboot·毕设
计算机毕设定制辅导-无忧学长2 小时前
《基于微信小程序的居家医疗陪护预约系统设计与实现》
java·spring boot·微信小程序·uniapp·居家医疗陪护预约系统
张张123y2 小时前
DSH 插件调试避坑:client.js 设置面板、热重载与高频报错排查表
开发语言·javascript·人工智能·开源·ecmascript·后端开发·ai agent
文丑颜不良啊3 小时前
LeetCode2221~2240题目解析
java·leetcode
秋饼4 小时前
Computer Use Agent Java 落地实战:感知-行动循环、执行器与安全围栏生产级实现
java·ai·技术分享·后端开发
冻柠檬飞冰走茶5 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
文丑颜不良啊5 小时前
LeetCode2161~2180题目解析
java·leetcode
FRing035 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
雪落漂泊5 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法