Java 枚举策略模式:用枚举替换 if-else 分发的三种绑定方式

2026年9月13日星期日·3305 字·17 分钟·
-浏览量
纯文本
学习文档Java设计模式枚举
AI 摘要- DeepSeek

用 Java 枚举承接按类型分发行为的 if-else 链:时间单位偏移与数据收集服务分发两个案例,覆盖三种绑定形式的选择与 ordinal 落库等高频坑。

封面图
Java 枚举策略模式:用枚举替换 if-else 分发的三种绑定方式 - 封面图
提示

本文解决日常开发中最常见的分支失控问题:按类型分发行为。案例取自项目里重构过的两段真实代码:时间单位枚举 TimeUnitEnum(抽象方法版)与数据收集分发枚举 DataCollectEnum(服务接口 + Optional 版)。重点审查项:查找走静态表且失败路径显式、枚举策略无状态、需要依赖注入的场景改用 Spring 策略 Map。

核心摘要#

  • 问题:类型定义、映射关系、算法实现散在同一个方法里,单位 code 是散落的字符串常量,拼错和漏匹配只能运行期暴露。
  • 方案:用枚举承载「类型 → 行为」映射,按行为依赖什么选三种绑定形式。
  • 边界:枚举常量在类加载期初始化,拿不到 Spring bean;需要依赖注入或运行时扩展改用 Spring 策略 Map。
  • 目标:新增分支 = 加一个常量;漏实现 = 编译失败;未知 code 的失败路径显式可见。

引子#

场景是调度系统按「间隔 + 单位」推算任务下次执行时间。配置存两个字段:resubmitInterval 和 resubmitIntervalUnit(SEC / MIN / HR / DAY)。第一版计算逻辑:

public Date nextRunTime(Date requestedStartDate, Integer interval, String unit) {
if ("SEC".equals(unit)) {
return DateUtil.offsetSecond(requestedStartDate, interval);
} else if ("MIN".equals(unit)) {
return DateUtil.offsetMinute(requestedStartDate, interval);
} else if ("HR".equals(unit)) {
return DateUtil.offsetHour(requestedStartDate, interval);
} else if ("DAY".equals(unit)) {
return DateUtil.offsetDay(requestedStartDate, interval);
}
return requestedStartDate;
}

"SEC" 字符串散落在每个计算点,拼错没有编译错误,漏匹配静默返回原时间;加时间、减时间、间隔校验各复制一份单位判断;新增单位要改所有老方法。项目实际的重构结果是下文的 TimeUnitEnum:类型定义、映射关系、算法实现收进一个枚举,新增分支等于新增一个常量。

背景知识#

  1. 枚举常量是进程级单例,由类加载机制创建(JLS §8.9)。
  2. 枚举可以声明抽象方法,每个常量在定义处覆写,漏实现直接编译失败。
  3. 时间偏移用 hutool 的 DateUtil(项目既有依赖)。

核心内容#

第一步:行为搬进常量(抽象方法版)#

MINUTE、HOUR 与 SECOND 同构(offsetMinute / offsetHour),此处省略,组装完成的完整成品见下文「实战演示一」:

public enum TimeUnitEnum {
SECOND("SEC", "秒") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetSecond(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetSecond(date, -interval);
}
},
MINUTE("MIN", "分钟") { /* 同构,省略 */ },
HOUR("HR", "小时") { /* 同构,省略 */ },
DAY("DAY", "天") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetDay(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetDay(date, -interval);
}
};
private final String code;
private final String info;
TimeUnitEnum(String code, String info) {
this.code = code;
this.info = info;
}
/** 加 / 减 interval 个当前单位。 */
public abstract Date addTime(Date date, Integer interval);
public abstract Date subTime(Date date, Integer interval);
// getCode() / getInfo() 从略
}
Date nextDay = TimeUnitEnum.DAY.addTime(horizonDay.getDateTo(), stockLt.intValue());

三种绑定形式#

形式适用条件案例
字段绑数据分支差异只是配置值单位秒数换算系数
抽象方法绑行为逻辑纯计算,只依赖入参addTime / subTime(案例一)
服务作参数逻辑要调 Spring bean,调用方传入execute(DataCollectService, ctx)(案例二)

字段绑数据的例子:分支差异只是数据时,一个换算系数字段就够,不必覆写方法:

SECOND("SEC", "秒", 1L),
MINUTE("MIN", "分钟", 60L),
HOUR("HR", "小时", 3600L),
DAY("DAY", "天", 86400L);
private final long seconds;
/** 间隔归一化为秒,用于跨单位比较。 */
public long toSeconds(long interval) {
return interval * seconds;
}

三种形式可混合使用:能用同一算法骨架表达就用字段,分支不同构才覆写,需要容器里的 bean 就把服务作为方法参数传入(案例二),枚举类加载期不依赖容器。

静态查找表:从线性扫描到静态 Map#

项目初版的查找方法:

public static TimeUnitEnum getEnumByCode(String code) {
for (TimeUnitEnum item : values()) {
if (item.getCode().equals(code)) {
return item;
}
}
return TimeUnitEnum.DAY;
}

两个问题:每次调用克隆数组再线性扫描,O(n);未知 code 静默返回 DAY,传错单位被按天重排且不留痕,上层补偿分支永远走不到。

改进版:

private static final Map<String, TimeUnitEnum> CODE_MAP = Arrays.stream(values())
.collect(Collectors.toMap(TimeUnitEnum::getCode, Function.identity()));
/** fail fast:脏配置拦在入口。 */
public static TimeUnitEnum getEnumByCode(String code) {
TimeUnitEnum unit = CODE_MAP.get(code);
if (unit == null) {
throw new IllegalArgumentException("未知时间单位 code: " + code);
}
return unit;
}
/** 允许降级的场景单独走可空查找,决策留在调用方。 */
public static TimeUnitEnum findOrNull(String code) {
return CODE_MAP.get(code);
}

失败路径三选一,全站保持一致:fail fast(对外接口)、Optional / 可空(允许跳过的批处理,见案例二)、默认值兜底(默认值必须经业务确认,代价是上层错误处理变成死代码,见案例一)。

与 Spring 策略模式的选型边界#

枚举常量在类加载期初始化,早于容器启动,构造器里拿不到任何 bean。

维度枚举策略Spring Map 策略(Map<String, Handler> 注入)
分支数量编译期固定运行时可扩展,新 bean 自动注册
依赖注入不支持,只能由调用方传入天然支持
分支完整性编译器强制,漏写编译失败无强制,漏注册运行期才暴露
状态必须无状态Handler 可以有状态、可配置
序列化与落库code 可直接映射字典表需自行维护 key 约定
适用规模十几个分支以内、逻辑稳定分支持续增长、逻辑重、需要 mock 单依赖

分支不超过十几个、逻辑纯计算,用枚举;需要多依赖协作或预期持续膨胀,用 Spring 策略。

实战演示一:时间单位偏移#

核心内容一节按「行为搬进常量」「三种绑定形式」「静态查找表」分步拆解了模式本身,这一节把三步组装成项目里落地的完整成品。先看最终的 TimeUnitEnum,四个常量全部展开,落库与报文反序列化的注解一并标上:

public enum TimeUnitEnum {
SECOND("SEC", "秒") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetSecond(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetSecond(date, -interval);
}
},
MINUTE("MIN", "分钟") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetMinute(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetMinute(date, -interval);
}
},
HOUR("HR", "小时") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetHour(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetHour(date, -interval);
}
},
DAY("DAY", "天") {
@Override
public Date addTime(Date date, Integer interval) {
return DateUtil.offsetDay(date, interval);
}
@Override
public Date subTime(Date date, Integer interval) {
return DateUtil.offsetDay(date, -interval);
}
};
/** 实体字段声明为枚举类型时,MyBatis-Plus 按此字段的值读写数据库列。 */
@EnumValue
private final String code;
private final String info;
TimeUnitEnum(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
/** 加 / 减 interval 个当前单位。 */
public abstract Date addTime(Date date, Integer interval);
public abstract Date subTime(Date date, Integer interval);
private static final Map<String, TimeUnitEnum> CODE_MAP = Arrays.stream(values())
.collect(Collectors.toMap(TimeUnitEnum::getCode, Function.identity()));
/** fail fast:脏配置拦在入口。 */
@JsonCreator
public static TimeUnitEnum getEnumByCode(String code) {
TimeUnitEnum unit = CODE_MAP.get(code);
if (unit == null) {
throw new IllegalArgumentException("未知时间单位 code: " + code);
}
return unit;
}
/** 允许降级的场景单独走可空查找,决策留在调用方。 */
public static TimeUnitEnum findOrNull(String code) {
return CODE_MAP.get(code);
}
}

两个注解打通枚举与外部数据:@EnumValue 让实体上的 TimeUnitEnum 字段与存 code 的数据库列直接互转;@JsonCreator 让报文里的 "SEC"、"MIN" 反序列化时走同一条「查表 + fail fast」路径,脏 code 在入口就被拦下。

枚举之上再包一层 MyDateUtils,调用方面对的是普通静态方法,不必感知分派细节,参数已是枚举、方法体就是纯委托:

public static Date addDate(Date sourceDate, Integer timeInterval, TimeUnitEnum unitEnum) {
return unitEnum.addTime(sourceDate, timeInterval);
}
public static Date subDate(Date sourceDate, Integer timeInterval, TimeUnitEnum unitEnum) {
return unitEnum.subTime(sourceDate, timeInterval);
}

调用点分两类。单位在编码期已知的,直接传常量,写错编译不过:

Date nextDay = MyDateUtils.addDate(horizonDay.getDateTo(), stockLt.intValue(), TimeUnitEnum.DAY);

单位来自数据库字符串的,先过查找表再计算,失败路径就地显式处理:写回备注留痕、跳过本条,批内其他任务不受影响:

private void copyOne(ScpConcurrentRequestsVO maxDateRequest) {
Date newDate;
try {
newDate = MyDateUtils.addDate(
maxDateRequest.getRequestedStartDate(),
maxDateRequest.getResubmitInterval(),
TimeUnitEnum.getEnumByCode(maxDateRequest.getResubmitIntervalUnit()));
} catch (IllegalArgumentException e) {
maxDateRequest.setCompletionComments("时间类型错误: " + maxDateRequest.getResubmitIntervalUnit());
remoteScpMasterControlService.updateById(maxDateRequest);
return;
}
// ... 后续复制逻辑
}

单测锁定两个行为:加减互逆覆盖全部常量(@EnumSource 遍历 values(),新增常量自动纳入),未知 code 确实 fail fast:

@ParameterizedTest
@EnumSource(TimeUnitEnum.class)
void addThenSubRestoresOriginalTime(TimeUnitEnum unit) {
Date base = new Date(1700000000000L);
Date restored = MyDateUtils.subDate(MyDateUtils.addDate(base, 5, unit), 5, unit);
assertEquals(base, restored);
}
@Test
void unknownCodeFailsFast() {
assertThatThrownBy(() -> TimeUnitEnum.getEnumByCode("WEEK"))
.isInstanceOf(IllegalArgumentException.class);
}

对照引子的痛点逐一收口:单位字符串只在枚举定义处出现一次;新增单位等于加一个常量、覆写两个方法,所有调用点不动,漏覆写编译失败;未知 code 在查找入口显式抛错,不再静默按天重排。

实战演示二:服务分发(接口 + Optional)#

场景:数据收集平台,一个入口按 collectCode 分发收集动作,动作实现在业务服务里。

public interface DataCollectService {
void collectMaterial(CollectContext ctx);
void collectOrder(CollectContext ctx);
void collectItems(CollectContext ctx);
}
@Getter
public enum DataCollectEnum {
MATERIAL("MATERIAL", "同步物料") {
@Override
public void execute(DataCollectService service, CollectContext ctx) {
service.collectMaterial(ctx);
}
},
ORDER("ORDER", "同步订单") {
@Override
public void execute(DataCollectService service, CollectContext ctx) {
service.collectOrder(ctx);
}
},
ITEM("ITEM", "ITEM 数据收集") {
@Override
public void execute(DataCollectService service, CollectContext ctx) {
service.collectItems(ctx);
}
};
private final String code;
private final String name;
DataCollectEnum(String code, String name) {
this.code = code;
this.name = name;
}
/** 统一操作入口,service 由调用方传入。 */
public abstract void execute(DataCollectService service, CollectContext ctx);
private static final Map<String, DataCollectEnum> CODE_MAP = Arrays.stream(values())
.collect(Collectors.toMap(DataCollectEnum::getCode, Function.identity()));
/** Optional 版查找:未知 code 返回 empty,跳过还是报错由调用方决定。 */
public static Optional<DataCollectEnum> getByCode(String code) {
return Optional.ofNullable(CODE_MAP.get(code));
}
public static String getNameByCode(String code) {
return getByCode(code).map(DataCollectEnum::getName).orElse("");
}
}

两条关键设计:

  1. 参数类型声明为接口。用 <T extends DataCollectService> 约束泛型也行;直接声明实现类类型,常量体里就要强转,((实际服务类) service) 这类写法就是这么来的。
  2. 未知 code 走 Optional。collectCode 是运营配置,未知时跳过并记日志,比抛异常温和;两个案例正好覆盖两种失败路径。

控制器一行完成分发:

@GetMapping("/collect")
public R collect(@RequestParam String collectCode, CollectContext ctx) {
DataCollectEnum.getByCode(collectCode)
.ifPresent(e -> e.execute(dataCollectService, ctx));
return R.ok();
}

服务接口的实现端可以是任何 bean;控制器自身实现了接口时,传 this 同样成立。业务参数超过三个时收成参数对象(CollectContext),别让 execute 的签名跟着业务字段膨胀。

踩坑点 & 注意事项#

坑 1:ordinal() 落库#

插入新常量会让后续所有序号位移,已落库数据语义静默错位。落库用显式 code 字段,ordinal() 只限同枚举内部使用。

坑 2:构造期引用静态查找表#

枚举常量先于其他静态字段初始化,构造路径读 CODE_MAP 拿到 null,编译通过、类加载期 NPE,堆栈只有一行 <clinit>。查找表只被静态方法读取,任何常量构造路径不碰它。

坑 3:常量里放可变状态#

常量是进程级单例,可变字段被所有请求线程共享,压测时出现时对时错且难复现。枚举只放不可变字段(code、info、函数引用),请求级状态走方法参数。

坑 4:传统 switch 没有穷举检查#

新增常量后传统 switch 静默走 default;switch 表达式(Java 14+)缺分支直接编译失败。分支调度优先用抽象方法,确需 switch 用表达式形式。

坑 5:删除或改名枚举值#

数据库和报文里的老 code 不会消失,删常量后历史数据反序列化直接报错。枚举只增不删,废弃常量标 @Deprecated 保留映射。

性能/对比数据#

方案分支查找新增分支改动点漏实现的暴露时机依赖注入
if-else 链O(n)改老方法Code review困难
传统 switch 语句O(1),编译器生成跳转表改老方法运行期,静默走 default困难
枚举抽象方法O(1),虚方法分派加一个常量编译期不支持
枚举 + 静态 MapO(1),HashMap加一个常量编译期或单测不支持
Spring Map 策略O(1),HashMap加一个 bean启动后首次调用,或依赖单测天然支持

初版 getEnumByCode 就是第一行的 O(n):每次调用克隆常量数组再线性扫描,静态表消除分配并把查找降到 O(1)。枚举常量类加载期创建一次,请求路径无策略对象分配;Spring Handler 同为单例,选型差异在依赖注入与扩展性,不在性能。

总结#

枚举策略把「类型 → 行为」映射交给编译器检查:类型定义、code 映射、算法收进一个枚举,新增分支只增常量,漏实现编译失败。两个案例覆盖两种接法:纯计算用抽象方法(TimeUnitEnum),依赖服务用接口参数(DataCollectEnum);失败路径三选一并全站一致:fail fast、Optional、经业务确认的默认值。分支稳定逻辑轻用枚举,需要依赖注入或持续膨胀用 Spring Map 策略。

参考资料#


提示

如果这篇文章对你有帮助,欢迎点赞收藏。有问题欢迎评论区交流。

Java 枚举策略模式:用枚举替换 if-else 分发的三种绑定方式
https://tblog.mmzhiku.xyz/posts/details-java-enum-strategy-pattern/
作者
MmzMing
发布于
2026-09-13
许可协议
CC BY-NC-SA 4.0
RAG 检索增强生成 10 种策略:分块、混合检索与重排序选型
这个博客《纯AI,零人工》

评论区

暂无歌词

暂未播放

0:00
0:00
目录
logo

隐私政策

更新日期: 2026 年 7 月 15 日
生效日期: 2026 年 7 月 15 日

适用范围#

本政策适用于 MmzMing 的博客(以下简称“本站”)。本站是个人博客,用于发布和分享内容;不提供账户注册、支付、定位或广告投放服务。访问本站、发表文章评论或在留言板留言前,请阅读本政策。

信息收集与使用#

本站只在提供内容、评论和留言功能,以及维护站点安全所需的范围内处理信息。

  • 访问与统计信息:访问页面时,统计服务可能处理访问时间、页面地址、来源页、浏览器和设备相关信息,用于了解内容访问情况、排查故障和改进站点。
  • 评论信息:使用文章评论功能时,Waline 可能处理您主动提交的昵称、邮箱、站点链接和评论内容;还可能处理 IP 地址等必要信息,用于防止垃圾评论、滥用和维护服务安全。评论内容、昵称和站点链接(如填写)可能公开展示在文章下方;邮箱不会公开展示。
  • 留言信息:留言板使用 Waline /guestbook/ 频道。Waline 可能处理您主动提交的昵称、可选邮箱、站点链接、留言内容和图片,以及浏览器、操作系统、IP 地址等必要的反滥用信息。默认情况下,留言图片以内嵌数据随留言提交;如站点维护者配置了远程图片上传接口,图片会先发送至该接口并在留言中保存返回的图片地址。留言内容、昵称、图片和站点链接(如填写)可能公开展示;邮箱和 IP 地址不会在留言板公开展示。

请不要在评论或留言中提交身份证件、银行卡、住址、密码或其他不必要的敏感个人信息。

第三方服务#

为实现本站功能,以下第三方会在各自服务范围内处理相关数据:

  • Umami:用于匿名化的网站访问统计和出站链接点击统计,帮助我了解本站的使用情况。
  • Waline:用于文章评论、留言板及访问量统计。服务会按照其自身规则处理您在评论或留言时提交的信息及必要的反滥用信息。
  • Cloudflare:可为本站提供静态资源分发和域名基础设施。
  • unpkg:用于加载 Waline 的前端脚本、样式和表情资源;请求这些资源时,您的浏览器会与该服务建立连接。

第三方服务可能有独立的隐私政策和数据保存规则。请在使用相关功能前查阅其规则;本站无法控制其独立的数据处理活动。

本站主要使用浏览器本地存储(Local Storage 或 Session Storage)保存使用偏好,例如主题颜色、明暗模式、文章列表视图和音乐播放设置。留言板会在本地保存匿名资料、未发送草稿和登录状态,以便恢复输入与会话;管理员登录状态仅保存在当前会话。

本站不主动设置用于广告定向的第一方 Cookie。评论、统计或资源服务可能按照其自身规则使用 Cookie 或类似技术。您可以通过浏览器设置查看、删除或限制 Cookie 和本地存储;清除后,部分偏好或互动状态可能会恢复为默认值,评论功能也可能受到影响。

信息公开、保存与安全#

评论和留言属于公开互动内容,提交后可能被搜索引擎收录、被他人引用或在缓存中短暂保留。请谨慎决定发布内容。除非您提出删除请求、内容违反规则或法律法规另有要求,公开内容会持续保留以维持讨论上下文。

本站会采取合理措施保护数据安全,包括使用 HTTPS、输入校验、内容转义和访问频率限制。但互联网传输和第三方服务均无法保证绝对安全,请理解并自行承担公开发布信息的相应风险。

你的权利#

你可以通过 784774835@qq.com 联系我,申请查询、更正或删除由本站直接保存的评论、留言或相关公开内容。为保护他人权益,请在请求中提供足以定位内容的信息,并说明你与该内容的关系;必要时可能需要进行合理核验。

对于由 Waline、Umami、Cloudflare 或 unpkg 独立处理的数据,你也可以直接向对应服务提供方行使相关权利。删除公开评论或留言后,第三方缓存、搜索引擎索引或他人转载的副本可能无法立即同步删除。

未成年人条款#

未满 14 周岁的未成年人应在监护人同意和指导下使用本站的评论、留言等互动功能。监护人如发现未成年人未经同意提交了个人信息,可通过上述联系方式与我联系,我会在合理范围内协助处理。

政策更新与联系#

我可能因本站功能或适用规则变化更新本政策,更新后的版本将在本站公布并标明日期。继续使用相关功能即表示你已阅读并理解更新后的政策。

如对本政策或数据处理有疑问,请联系 784774835@qq.com。

用户协议

更新日期: 2026 年 5 月 19 日
生效日期: 2026 年 5 月 19 日

适用范围#

本协议适用于你访问 MmzMing 的博客,以及使用文章评论、留言板等互动功能的行为。继续浏览本站或提交评论、留言,即表示你已阅读、理解并同意遵守本协议及本站的隐私政策。

评论及留言规则#

请在交流中保持友善、理性和尊重。你不得利用本站发布、传播或实施以下行为:

  • 发布任何违反中华人民共和国法律法规的内容。
  • 发布任何侵犯他人合法权益的内容,包括但不限于隐私、名誉、肖像、著作权、商标权和其他知识产权。
  • 恶意攻击、辱骂、骚扰、威胁、歧视其他用户或任何第三方。
  • 发布垃圾广告、恶意推广、刷屏、灌水,或与讨论主题明显无关的重复内容。
  • 利用本站进行网络诈骗、钓鱼、传播恶意软件,或发布可能危害网络和信息安全的内容。
  • 绕越或试图绕越本站的审核、限流、封禁等管理措施。
  • 冒充他人、伪造身份,或收集、公开他人的个人信息。

内容与访问管理#

你应对自己发布的评论和留言负责,并保证拥有发布该等内容所需的合法权利。论坛管理员有权在不另行通知的情况下删除违规内容、限制或封禁违规账号,或限制其继续使用本站互动功能。

如发现涉嫌违法犯罪、严重侵权或危及本站安全的内容,本站可保留相关记录,并在法律法规要求或必要时向有关部门提供协助。对管理措施有疑问时,可通过文末联系方式说明情况;本站会结合实际情况处理,但不承诺恢复已删除内容或访问权限。

知识产权与内容授权#

本站原创文章、页面设计和其他受保护内容的权利归作者或权利人所有。未经授权,请勿复制、转载、镜像或用于商业用途;法律法规允许的合理使用除外。

你发布评论或留言时,授予本站为展示、存储、备份、审核、删除和维护互动功能所必需的非独占、免费的使用许可。该许可不改变你对原创内容依法享有的权利。

免责声明#

本站内容仅用于个人记录、学习交流和一般信息参考,不构成任何专业意见、承诺或担保。你应结合自身情况独立判断,并对据此采取的行动负责。

评论、留言和外部链接中的内容由其发布者或运营者负责,不代表本站立场。本站会在合理范围内处理明显违规内容,但不保证所有内容均及时发现,也不对第三方网站的可用性、内容、安全性或隐私实践承担责任。

因网络故障、不可抗力、第三方服务异常、维护升级或超出合理控制范围的原因导致本站暂时无法访问、内容延迟或数据丢失的,本站会尽力恢复,但不承担由此产生的间接损失。

未成年人条款#

未满 14 周岁的未成年人应在监护人同意和指导下使用评论、留言等互动功能。监护人应协助未成年人理解本协议,并对其使用行为进行必要的引导。

其他条款#

我可以根据本站功能、管理需要或法律法规变化更新本协议,更新后的版本将在本站公布并标明日期。继续使用本站即视为接受更新后的协议。

本协议的订立、执行和解释适用中华人民共和国法律。因本协议或使用本站产生争议时,双方应先友好协商;协商不成的,依法向有管辖权的人民法院解决。

如对本协议或内容管理有疑问,请联系 784774835@qq.com。

复制成功,转载请标注本文地址