Skip to content

源码:labs/java/bridge-hybrid/contract-consistency-simulation/src/ContractConsistencySimulation.java ​

  • 原始路径:labs/java/bridge-hybrid/contract-consistency-simulation/src/ContractConsistencySimulation.java
  • 类型:java
java
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 多端一致性契约仿真:契约升级的向后兼容与破坏性变更。
 *
 * 对应 docs 05-bridge-hybrid/03-cross-platform-consistency-design.md:
 * - 单一事实源:契约只在 Schema 定义一处,多端按契约解析
 * - 三个场景演示:加可选字段(兼容)/ 字段类型变更(破坏)/ 缺必填字段(破坏)
 *
 * 纯 Java CLI(无外部依赖,Map 模拟 JSON 对象)。
 * 运行:javac -d out src/ContractConsistencySimulation.java && java -cp out ContractConsistencySimulation
 */
public class ContractConsistencySimulation {

    public static void main(String[] args) {
        System.out.println("========== 1. 老客户端(v1) 解析 v1 数据 ==========");
        Map<String, Object> serverV1 = json("userId", "10086", "name", "Alex");
        System.out.println("  端 A (v1) 解析: " + parseV1(serverV1));

        System.out.println();
        System.out.println("========== 2. 契约升级:加【可选】字段(向后兼容)==========");
        Map<String, Object> serverV2Optional = json(
                "userId", "10086", "name", "Alex", "avatar", "https://cdn/a.png");
        System.out.println("  端 A (v1) 解析 v2 数据(未知字段被忽略): " + parseV1(serverV2Optional) + "  ✅ 兼容");

        System.out.println();
        System.out.println("========== 3. 事故 1:字段【类型变更】(破坏性)==========");
        // 服务端把 name 从 String 改成数组("支持多语言昵称"),老客户端 String 强转崩溃
        Map<String, Object> serverV2TypeChanged = json(
                "userId", "10086",
                "name", new String[]{"Alex", "阿历克斯"});
        try {
            String name = (String) serverV2TypeChanged.get("name"); // 老端按 String 取
            System.out.println("  端 A (v1) 强转成功: " + name);
        } catch (ClassCastException e) {
            System.out.println("  端 A (v1) 强转崩溃: ClassCastException(String[] 无法转 String)❌ 类型变更即契约破坏");
        }

        System.out.println();
        System.out.println("========== 4. 事故 2:服务端异常返回【缺必填字段】==========");
        // 服务端降级/异常时返回缺 userId 的脏数据,老端业务逻辑空指针
        Map<String, Object> serverBadData = json("name", "Alex"); // 缺 userId
        String userId = (String) serverBadData.get("userId");
        if (userId == null) {
            System.out.println("  端 A (v1) 拿到 userId=null → 后续业务逻辑 NPE / 展示异常 ❌");
            System.out.println("  修法:服务端异常时返回统一错误码,而不是缺字段的 200");
        }

        System.out.println();
        System.out.println("========== 6. 契约漂移 CI 强校验 ==========");
        // 契约表(单一事实源):通道名 -> 版本
        Map<String, Integer> contractTable = new LinkedHashMap<>();
        contractTable.put("getDeviceInfo", 1);
        contractTable.put("openGallery", 2);
        contractTable.put("requestPayment", 1);
        // 运行时注册表:开发者新增通道却忘了登记契约 → 漂移
        Map<String, Integer> registered = new LinkedHashMap<>(contractTable);
        registered.put("shareToChat", 1); // 注册了却没进契约表
        boolean setOk = registered.keySet().equals(contractTable.keySet());
        boolean verOk = contractTable.entrySet().stream()
                .allMatch(e -> registered.getOrDefault(e.getKey(), -1).equals(e.getValue()));
        boolean ciPass = setOk && verOk;
        System.out.println("  校验① 注册通道集合 == 契约表集合: " + (setOk ? "✅" : "❌ 漂移(shareToChat 未登记)"));
        System.out.println("  校验② 同名通道版本一致: " + (verOk ? "✅" : "❌"));
        System.out.println("  CI 结果: " + (ciPass ? "通过 ✅" : "失败,阻断构建 ❌"));

        System.out.println();
        System.out.println("========== 7. 结论 ==========");
        System.out.println("  · 加字段:必须可选(optional),旧端忽略未知字段 → 兼容");
        System.out.println("  · 改类型 / 删字段 / 必填化:都是破坏性变更,需版本兜底(v1/v2 双契约)或全端同步升级");
        System.out.println("  · 错误语义:异常返回错误码(如 422 + error_code),不返回缺字段脏数据");
        System.out.println("  · 契约漂移:注册表与契约表不一致 / 版本不一致 → CI 强校验阻断构建");
    }

    /** 契约 v1 解析:只取 userId + name,忽略未知字段 */
    static Map<String, Object> parseV1(Map<String, Object> data) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("userId", data.get("userId"));
        result.put("name", data.get("name"));
        return result;
    }

    /** 简化 JSON 对象构造 */
    static Map<String, Object> json(Object... kv) {
        Map<String, Object> map = new LinkedHashMap<>();
        for (int i = 0; i < kv.length; i += 2) map.put((String) kv[i], kv[i + 1]);
        return map;
    }
}

站点构建时间:2026/8/24 23:43:17