应使用适配器模式封装协议转换逻辑,而非在业务代码中硬编码转换调用;否则违反开闭原则、无法正确处理真实xml特性、导致业务与协议强耦合。

直接用适配器模式封装转换逻辑,而不是在业务代码里硬塞 convertXmlToJson() 调用——否则每加一个新服务就得改一次 shipOrder(),等于把胶水写进了主干。
为什么不能在业务层手动做 XML→JSON 转换
临时补丁式写法(比如在 LogisticsClient.shipOrder() 里判断 useJsonService 再调 convertXmlToJson())会导致三个实际问题:
- 每次接入新物流商(如 ProtocolBuffers、YAML、gRPC),都得往同一个方法里加
if-else分支,违反开闭原则 -
convertXmlToJson()这种字符串替换(xml.replace("Xml", "Json"))根本不能处理嵌套结构、属性、CDATA、命名空间等真实 XML 特性 - 业务逻辑和数据协议强耦合,单元测试必须 mock 全链路,无法单独验证“XML 输入 → JSON 输出”是否正确
适配器类必须实现统一接口,且只依赖抽象
关键不是“怎么转”,而是“谁来转、在哪转”。定义一个目标接口 LogisticsService,所有适配器都实现它:
public interface LogisticsService {
String sendRequest(String payload);
}
然后为旧系统写类适配器:
public class XmlLogisticsAdapter implements LogisticsService {
private final XmlLogisticsService delegate;
public XmlLogisticsAdapter(XmlLogisticsService delegate) {
this.delegate = delegate;
}
@Override
public String sendRequest(String payload) {
// payload 是 JSON,但旧服务只认 XML → 需反向转换
String xml = jsonToXml(payload); // 真实实现需解析 JSON 再构造 XML
return delegate.sendXmlRequest(xml);
}
}
为新服务写对象适配器:
public class JsonLogisticsAdapter implements LogisticsService {
private final JsonLogisticsService delegate;
public JsonLogisticsAdapter(JsonLogisticsService delegate) {
this.delegate = delegate;
}
@Override
public String sendRequest(String payload) {
// payload 是 XML,但新服务只认 JSON → 正向转换
String json = xmlToJson(payload); // 真实实现用 xmltodict 或 Jackson
return delegate.sendJsonRequest(json);
}
}
业务代码从此只依赖 LogisticsService:
public class OrderProcessor {
private final LogisticsService logistics;
public OrderProcessor(LogisticsService logistics) {
this.logistics = logistics;
}
public void process(String orderXml) {
logistics.sendRequest(orderXml); // 输入始终是 XML,输出由适配器屏蔽
}
}
真实项目中 XML→JSON 转换不能靠字符串替换
线上 XML 数据通常含以下成分,简单 replace() 必然失败:
- 属性:
<item id="123" type="book"></item>→ JSON 中应转为{"id": "123", "type": "book", "_text": "..."} - CDATA:
<content>Hello]]></content>→ 需原样保留内容,不能被 XML 解析器转义 - 命名空间:
<order xmlns:ns="http://example.com"></order>→ JSON 里得扁平化或保留前缀 - 重复子元素:
<item>a</item><item>b</item>→ 应转为数组["a", "b"],而非单个字符串
推荐方案(按语言):
- Java:用
Jackson的XmlMapper+ObjectMapper,先转 Java Bean 再转 JSON,能自动处理属性、CDATA、命名空间配置 - Python:用
xmltodict.parse(),它默认将属性转为@attr键,重复元素自动成 list,比手写 DOM 遍历稳得多 - Node.js:用
fast-xml-parser,开启ignoreAttributes: false和parseTrueNumberOnly: true可控性更强
适配器的生命周期和错误边界必须显式管理
适配器不是万能胶布,它本身会引入新风险点:
- XML 解析失败(格式错误、编码不一致、超大文件)不能让
sendRequest()抛出NullPointerException,必须包装为明确的LogisticsProtocolException - 转换后的 JSON 字段缺失(如 XML 里没
<price></price>,但 JSON 接口强制要求)需在适配器内补默认值或抛结构校验异常,不能等到下游服务报 400 - 如果旧系统返回的是 SOAP XML,得额外剥离
<envelope></envelope>外层,这部分逻辑必须封在适配器里,业务层无感
最易被忽略的一点:适配器不该持有状态。比如把 XmlMapper 实例作为字段反复复用是可以的,但若缓存了某次解析结果并用于下次请求,就会在并发场景下出错。











