前言:當你要同時對接 17 個電商平台
在多通路電商系統中,我們需要整合多個平台:
| 平台類型 | 範例 | 特性 |
|---|---|---|
| 綜合電商 | 蝦皮、Momo、Yahoo、PChome | 訂單量大、API 複雜 |
| 開店平台 | Shopify、Shopline、91APP | 彈性高、客製化多 |
| 國際平台 | 樂天、Coupang、Amazon | 多語系、跨境物流 |
解決方案:工廠模式 + 策略模式
Step 1:定義統一介面
所有平台都必須實作這個介面:
* 電商平台動作介面
* 所有平台整合都必須實作這個介面
*/
public interface ChannelAction {
// 取得平台設定(API URL、版本等)
ChannelSetting getSetting();
// 取得平台授權 Token
TokenResult getAccessToken(Merchant merchant);
// 驗證必要資料是否齊全
boolean validateRequired(ActionRequest request);
// 執行實際動作(同步訂單、更新庫存等)
ActionResult execute(ActionRequest request);
}
Step 2:每個平台各自實作
蝦皮實作範例:
public class ShopeeAction implements ChannelAction {
@Override
public ChannelSetting getSetting() {
return ChannelSetting.builder()
.apiUrl(“https://partner.shopeemobile.com”)
.version(“v2”)
.authType(AuthType.OAUTH2)
.build();
}
@Override
public TokenResult getAccessToken(Merchant merchant) {
// 蝦皮使用 OAuth2 + 簽章驗證
String signature = generateSignature(merchant);
return callShopeeAuthAPI(merchant, signature);
}
@Override
public ActionResult execute(ActionRequest request) {
// 呼叫蝦皮 API 執行動作
return callShopeeAPI(request);
}
}
Momo 實作範例:
public class MomoAction implements ChannelAction {
@Override
public ChannelSetting getSetting() {
return ChannelSetting.builder()
.apiUrl(“https://api.momo.com.tw”)
.version(“v1”)
.authType(AuthType.API_KEY)
.build();
}
@Override
public TokenResult getAccessToken(Merchant merchant) {
// Momo 使用 API Key 驗證
return TokenResult.of(merchant.getMomoApiKey());
}
@Override
public ActionResult execute(ActionRequest request) {
// 呼叫 Momo API 執行動作
return callMomoAPI(request);
}
}
Step 3:工廠類別統一管理
public class ChannelFactory {
private final Map<ChannelType, ChannelAction> actionMap;
// Spring 自動注入所有 ChannelAction 實作
public ChannelFactory(List<ChannelAction> actions) {
this.actionMap = actions.stream()
.collect(Collectors.toMap(
action -> action.getSetting().getChannelType(),
action -> action
));
}
/**
* 根據通路類型取得對應的實作
*/
public ChannelAction getAction(ChannelType channelType) {
ChannelAction action = actionMap.get(channelType);
if (action == null) {
throw new UnsupportedChannelException(
“不支援的通路: “ + channelType
);
}
return action;
}
}
使用方式
業務邏輯層只需要這樣呼叫:
public class OrderSyncService {
@Autowired
private ChannelFactory channelFactory;
public SyncResult syncOrders(ChannelType channel, Merchant merchant) {
// 1. 取得對應的通路實作
ChannelAction action = channelFactory.getAction(channel);
// 2. 取得授權 Token
TokenResult token = action.getAccessToken(merchant);
// 3. 執行同步
ActionRequest request = ActionRequest.builder()
.merchant(merchant)
.token(token)
.actionType(ActionType.SYNC_ORDERS)
.build();
return action.execute(request);
}
}
新增平台有多簡單?
假設要新增 Coupang 韓國平台:
public class CoupangAction implements ChannelAction {
@Override
public ChannelSetting getSetting() {
return ChannelSetting.builder()
.apiUrl(“https://api-gateway.coupang.com”)
.version(“v2”)
.authType(AuthType.HMAC)
.build();
}
// … 實作其他方法
}
| 步驟 | 工作內容 | 影響範圍 |
|---|---|---|
| 1 | 建立 CoupangAction 類別 | 只有新檔案 |
| 2 | 實作 ChannelAction 介面 | 只有新檔案 |
| 3 | 加上 @Component 註解 | 只有新檔案 |
| 4 | 完成!Spring 自動註冊 | 零修改現有程式 |
設計模式總結
| 模式 | 用途 | 在這裡的應用 |
|---|---|---|
| 策略模式 | 定義演算法家族,讓它們可互換 | 每個平台是一個策略 |
| 工廠模式 | 封裝物件建立邏輯 | 根據通路類型取得實作 |
| 依賴注入 | 解耦合 | Spring 自動管理 |
- 新增通路:從 2-3 個月縮短到 2-3 週
- 維護成本:改一個平台不影響其他平台
- 測試:每個平台可以獨立單元測試
為什麼不用其他方案?
| 方案 | 優點 | 缺點 | 結論 |
|---|---|---|---|
| if-else 判斷 | 簡單直接 | 每次加平台要改核心程式碼 | 小規模可用,超過 3 個平台就很痛苦 |
| Switch Case | 比 if-else 清楚 | 還是要改核心程式碼 | 同上 |
| 反射 + 設定檔 | 完全不改程式碼 | 除錯困難、IDE 無法追蹤 | 過度設計,維護成本高 |
| 工廠 + 策略 | 新增只加檔案、Spring 自動註冊 | 需要理解設計模式 | 中大型系統的最佳平衡 |
實戰踩坑
蝦皮某次 API 升級,回傳欄位名稱從 order_sn 改成 ordersn。因為每個平台有獨立的 Action 類別,我們只需要改 ShopeeAction,其他 16 個平台完全不受影響。如果用 if-else,改錯一行就全部爆炸。
新人寫好 CoupangAction 卻沒加 @Component,Spring 沒註冊到 Factory。呼叫時直接噴 UnsupportedChannelException。後來在程式碼審查加入檢查項:「確認新 Action 有 @Component」。
最初 ChannelAction 只有 execute() 一個方法。後來發現有些平台需要 OAuth 刷新 Token、有些需要 Webhook 處理。介面改了三次才穩定。教訓:先做 3-5 個平台再抽象,別一開始就過度設計。
系列導航
| ◀ 上一篇 導讀篇 |
📚 返回目錄 | 下一篇 ▶ Kafka 事件驅動 |