Java 多例设计模式:用类模拟枚举实现季节管理

📅 2026/7/29 17:01:20
Java 多例设计模式:用类模拟枚举实现季节管理
一、引言在 Java 5 引入原生enum之前或者在我们需要更灵活的“类枚举”结构时多例设计模式Multiton Pattern是一种非常实用的技巧。本文通过一个“四季”的案例讲解如何用 Java 类来模拟枚举展示其中的设计思想和代码实现。二、多例模式的核心思想多例模式是单例模式的扩展。它要求一个类有固定数量的实例并且这些实例在类内部被提前创建好。外部无法随意new对象只能通过指定的静态方法获取。常用于代表固定数量的状态如四季、红绿灯数据库连接池固定数量的连接对象在旧版 Java 中模拟枚举下面的流程图展示了多例模式的典型工作流程类加载时一次性创建所有实例外部通过静态方法按编号获取对应的实例对象。case 1case 2case 3case 4default类加载创建静态常量实例SPRING / SUMMER / AUTUMN / WINTER私有构造初始化name, code 等属性外部调用 static 方法fromCode(int code)switch (code)返回 SPRING返回 SUMMER返回 AUTUMN返回 WINTER抛出 IllegalArgumentException三、原始实现回顾我们先来看一段原始的“四季管理”代码classJJ{// 4个固定的实例代表四季privatefinalstaticJJCnewJJ(春季);privatefinalstaticJJXnewJJ(夏季);privatefinalstaticJJQnewJJ(秋季);privatefinalstaticJJDnewJJ(冬季);privateStringseasonName;// 季节名称// 构造方法私有防止外部创建新实例privateJJ(StringseasonName){this.seasonNameseasonName;}// 根据编号返回对应的季节实例publicstaticJJgetSeason(intsign){switch(sign){case1:returnC;case2:returnX;case3:returnQ;case4:returnD;default:returnnull;}}OverridepublicStringtoString(){returnthis.seasonName;}}publicclassTest{publicstaticvoidmain(String[]args){System.out.println(JJ.getSeason(1));// 输出春季}}运行结果春季3.1 代码分析私有构造方法private JJ(...)确保外部无法new对象。静态常量C、X、Q、D是类加载时一次创建并固定的四个实例。对外接口getSeason(int sign)通过编号返回对应实例对外屏蔽了内部实例的管理。toString 重写打印时输出具体季节名称而不是内存地址。这就实现了用普通 Java 类模拟枚举的效果。四、优化版本更健壮的实现上面的原始版本虽然可用但在命名、异常处理和扩展性上仍有提升空间。下面我们重构一版/** * 四季多例类优化版 */classSeason{// 定义四个固定实例publicstaticfinalSeasonSPRINGnewSeason(春季,1);publicstaticfinalSeasonSUMMERnewSeason(夏季,2);publicstaticfinalSeasonAUTUMNnewSeason(秋季,3);publicstaticfinalSeasonWINTERnewSeason(冬季,4);privatefinalStringname;// 季节中文名privatefinalintcode;// 季节编号// 私有构造privateSeason(Stringname,intcode){this.namename;this.codecode;}// 根据编号获取实例优化后不返回 nullpublicstaticSeasonfromCode(intcode){switch(code){case1:returnSPRING;case2:returnSUMMER;case3:returnAUTUMN;case4:returnWINTER;default:thrownewIllegalArgumentException(无效的季节编号: code);}}// Getter 方法publicStringgetName(){returnname;}publicintgetCode(){returncode;}OverridepublicStringtoString(){returnSeason{namename, codecode};}}publicclassTestSeason{publicstaticvoidmain(String[]args){SeasonspringSeason.fromCode(1);System.out.println(spring);// 输出完整对象信息System.out.println(spring.getName());// 输出春季System.out.println(Season.SPRINGspring);// true同一个对象}}4.1 优化点说明优化项原始版本优化版本命名规范变量名C、X等不直观SPRING、SUMMER等见名知意异常处理错误编号返回null抛出IllegalArgumentException更安全信息完整度只有名称增加code编号toString信息更丰富直接访问必须通过方法获取静态常量public可直接用Season.SPRING下面的类图展示了优化版Season类的完整结构包括私有构造方法、静态常量实例、实例方法以及它们之间的关系被调用Season-String name-int codeSeason SPRINGSeason SUMMERSeason AUTUMNSeason WINTER-Season(String name, int code)fromCode(int code) : SeasongetName() : StringgetCode() : inttoString() : StringTestSeasonmain(String[] args) : void私有构造方法确保外部无法new对象\n静态常量在类加载时一次性创建\nfromCode()方法提供安全的实例获取五、多例模式 vs Java 枚举Java 5 之后引入了enum关键字上面用类模拟的功能现在可以直接用枚举实现enumSeasonEnum{SPRING(春季,1),SUMMER(夏季,2),AUTUMN(秋季,3),WINTER(冬季,4);privatefinalStringname;privatefinalintcode;SeasonEnum(Stringname,intcode){this.namename;this.codecode;}publicStringgetName(){returnname;}publicintgetCode(){returncode;}}可以看到enum的写法更简洁而且天然保证了实例的唯一性和线程安全性。多例模式更适用于需要对实例数量进行动态控制的场景如连接池而不只是简单的固定枚举。六、总结本文从一个“四季”案例出发展示了用 Java 类实现多例模式、模拟枚举的过程并进行了代码规范化和健壮性优化最后对比了原生枚举的写法。掌握多例模式不仅有助于理解单例的演化也能在特殊业务场景中提供更灵活的解决方案。扩展思考如果需求是“根据数据库配置动态决定有几个实例”那多例模式的“私有构造静态缓存”设计就会比枚举更适合因为枚举的实例数量在编译时就固定了。