软件SDK版本与服务器端API版本不一致是很常见的。优秀的SDK可以优雅地处理这种版本差异,并与潜在的API变更兼容。
在Android应用中使用的Java 对于SDK来说,版本兼容性尤为重要,因为用户更新应用程序的速度往往很慢。应用程序不应因使用旧版本的SDK而崩溃。
Java枚举的动态兼容性并不理想。以下是宠物店API的例子:
假设我们设计了代表订单状态的Java枚举:
立即学习“Java免费学习笔记(深入);
enum PetOrderStatus { PLACED, APPROVED, DELIVERED, }
用户发现枚举比字符串更方便,因为它可以清楚地指示所有可能的状态,并且可以使用switch表达式处理:
String displayText = switch (petOrderStatus) { case PLACED -> "Your order was placed and is being reviewed."; case APPROVED -> "Your order was approved."; case DELIVERED -> "Your order was delivered!"; };
但是,如何将API响应中的字符串转换为枚举常量呢?最常见的方法是使用valueOf():
PetOrderStatus petOrderStatus = PetOrderStatus.valueOf(statusString.toUpperCase());
该方法存在潜在问题:API变更。
假设产品经理要求增加“运输”状态。我们更新SDK:
enum PetOrderStatus { PLACED, APPROVED, IN_TRANSIT, DELIVERED, }
String displayText = switch (petOrderStatus) { case PLACED -> "Your order was placed and is being reviewed."; case APPROVED -> "Your order was approved."; case IN_TRANSIT -> "Your order is on the way!"; case DELIVERED -> "Your order was delivered!"; };
部署后,我们收到了崩溃报告:
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant PetOrderStatus.IN_TRANSIT at java.lang.Enum.valueOf(Enum.java) at PetOrderStatus.valueOf(PetOrderStatus.java)
这是因为旧SDK无法识别IN__TRANSIT。valueOf()遇到未知值时,方法会抛出异常。
解决方案
如何避免这种情况?使用Optional的方案是一个方案
更强大的解决方案是存储原始API值,并访问原始值和枚举:
public final class PetOrderStatus { private final String value; private PetOrderStatus(String value) { this.value = value; } public static PetOrderStatus of(String value) { return new PetOrderStatus(value); } public String _value() { return value; } public Value value() { return switch (value) { case "PLACED" -> Value.PLACED; case "APPROVED" -> Value.APPROVED; case "DELIVERED" -> Value.DELIVERED; default -> Value._UNKNOWN; }; } public enum Value { PLACED, APPROVED, DELIVERED, _UNKNOWN, } }
用户可以这样使用:
String displayText = switch (petOrderStatus.value()) { case PLACED -> "Your order was placed and is being reviewed."; case APPROVED -> "Your order was approved."; case DELIVERED -> "Your order was delivered!"; case _UNKNOWN -> "Your order status is: " + petOrderStatus._value(); };
该设计的优点:
- 保留了包括详细性检查在内的枚举优势。
- 能够处理未知状态,并使用原始API值。
API变更:第二部分:
API变更后,使用新的SDK设计不会崩溃。旧版本的应用程序将显示“Your order status is: IN_TRANSIT”。如果我们更新SDK和应用程序,并将IN_TRANSIT添加到枚举中,用户可以在下次更新后看到正确的文本。
以上是Java枚举兼容的详细内容。请关注图灵教育的其他相关文章!
