当前位置: 首页 > news >正文

Leather Dress Collection 代码重构展示:将冗长Java代码优化为优雅设计模式

Leather Dress Collection 代码重构展示:将冗长Java代码优化为优雅设计模式

最近在整理一些老项目,翻出来一段典型的“祖传代码”。这段代码功能是完整的,但读起来就像在走迷宫,维护起来更是让人头疼。正好,我们可以用它来展示一下,如何运用设计模式的思想,将一段结构混乱的业务代码,重构得清晰、优雅且易于维护。

今天要处理的代码,是一个简单的订单价格计算器。它根据不同的用户类型(普通用户、VIP用户、内部员工)和不同的商品类型(普通商品、折扣商品、秒杀商品),应用不同的折扣策略。原始版本把所有逻辑都塞在了一个巨大的if-else块里,我们一起来看看如何“拯救”它。

1. 原始代码:一个经典的“坏味道”案例

我们先看看这段需要被重构的代码。为了聚焦问题,我简化了一些细节,但核心的“坏味道”都保留了下来。

public class PriceCalculator { public double calculatePrice(String userType, String productType, double originalPrice) { double discount = 0.0; double finalPrice = originalPrice; // 根据用户类型计算折扣 if ("VIP".equals(userType)) { if ("DISCOUNT".equals(productType)) { discount = 0.20; // VIP买折扣商品额外折上折 } else if ("SEC_KILL".equals(productType)) { discount = 0.10; // VIP买秒杀商品也有小折扣 } else { discount = 0.15; // VIP买普通商品 } } else if ("INTERNAL".equals(userType)) { discount = 0.30; // 内部员工统一折扣 } else { // 普通用户 if ("DISCOUNT".equals(productType)) { discount = 0.10; } else if ("SEC_KILL".equals(productType)) { discount = 0.05; } // 普通商品无折扣 } finalPrice = originalPrice * (1 - discount); // 一些额外的费用规则,同样混乱 double extraFee = 0.0; if ("INTERNAL".equals(userType)) { extraFee = 0; // 内部员工免运费 } else { if (finalPrice < 50) { extraFee = 5.0; // 小单运费 } if ("SEC_KILL".equals(productType)) { extraFee += 2.0; // 秒杀商品加收服务费 } } return finalPrice + extraFee; } }

这段代码的问题非常典型:

  1. 可读性差:多层嵌套的if-else语句,理解业务逻辑需要在大脑里层层解析。
  2. 可维护性低:如果想增加一种新的用户类型(比如“超级VIP”)或者新的商品类型,必须深入这个庞大的方法内部修改,很容易引入错误。
  3. 可测试性差:由于所有逻辑耦合在一起,很难为每一种具体的折扣组合编写独立的单元测试。
  4. 违反开闭原则:对扩展开放,对修改关闭。这里每次修改都意味着要修改这个核心方法。

我们的目标,就是把这些纠缠在一起的逻辑,用设计模式梳理开来。

2. 重构之旅:识别模式与解耦逻辑

面对这样的代码,第一步不是直接动手改,而是分析。我们发现,折扣的计算逻辑和额外费用的计算逻辑,都可以根据“用户类型”和“商品类型”这两个维度进行抽象。这正好是策略模式(Strategy Pattern)的用武之地。我们可以为不同的折扣策略和费用策略定义独立的算法族。

同时,创建这些策略对象的过程,如果变得复杂,可以用工厂模式(Factory Pattern)来封装,让客户端代码更简洁。

2.1 第一步:定义折扣策略接口与实现

我们把折扣计算这部分单独抽出来。

// 折扣策略接口 public interface DiscountStrategy { double calculateDiscount(String productType, double originalPrice); } // VIP用户折扣策略 public class VipDiscountStrategy implements DiscountStrategy { @Override public double calculateDiscount(String productType, double originalPrice) { switch (productType) { case "DISCOUNT": return originalPrice * 0.20; case "SEC_KILL": return originalPrice * 0.10; default: // 普通商品 return originalPrice * 0.15; } } } // 内部员工折扣策略 public class InternalStaffDiscountStrategy implements DiscountStrategy { @Override public double calculateDiscount(String productType, double originalPrice) { // 内部员工统一折扣,与商品类型无关 return originalPrice * 0.30; } } // 普通用户折扣策略 public class RegularUserDiscountStrategy implements DiscountStrategy { @Override public double calculateDiscount(String productType, double originalPrice) { switch (productType) { case "DISCOUNT": return originalPrice * 0.10; case "SEC_KILL": return originalPrice * 0.05; default: return 0.0; // 普通商品无折扣 } } }

看,这样一来,每种用户类型的折扣逻辑都被封装在了自己的类里,清晰独立。如果要加一个“超级VIP”,只需要新建一个SuperVipDiscountStrategy类即可。

2.2 第二步:定义额外费用策略接口与实现

同样地,我们把令人头疼的额外费用规则也抽离出来。

// 额外费用策略接口 public interface ExtraFeeStrategy { double calculateExtraFee(String productType, double finalPrice); } // 内部员工费用策略(免运费等) public class InternalStaffFeeStrategy implements ExtraFeeStrategy { @Override public double calculateExtraFee(String productType, double finalPrice) { return 0.0; // 内部员工全免 } } // 普通用户费用策略 public class RegularUserFeeStrategy implements ExtraFeeStrategy { @Override public double calculateExtraFee(String productType, double finalPrice) { double fee = 0.0; if (finalPrice < 50) { fee += 5.0; } if ("SEC_KILL".equals(productType)) { fee += 2.0; } return fee; } }

2.3 第三步:创建策略工厂

现在我们有了一堆策略类,需要一个地方来管理它们,根据传入的类型返回正确的策略对象。这里我们用简单的工厂模式。

// 策略工厂 public class StrategyFactory { // 获取折扣策略 public static DiscountStrategy getDiscountStrategy(String userType) { switch (userType) { case "VIP": return new VipDiscountStrategy(); case "INTERNAL": return new InternalStaffDiscountStrategy(); case "REGULAR": default: return new RegularUserDiscountStrategy(); } } // 获取费用策略 public static ExtraFeeStrategy getExtraFeeStrategy(String userType) { if ("INTERNAL".equals(userType)) { return new InternalStaffFeeStrategy(); } else { return new RegularUserFeeStrategy(); } } }

工厂类把对象创建的细节隐藏了起来。未来如果创建逻辑变复杂(比如需要从配置读取,或使用原型模式),也只需要修改这个工厂类。

2.4 第四步:重构核心计算器

最后,我们来看重构后的PriceCalculator,现在它变得多么清爽。

public class RefactoredPriceCalculator { public double calculatePrice(String userType, String productType, double originalPrice) { // 1. 通过工厂获取策略 DiscountStrategy discountStrategy = StrategyFactory.getDiscountStrategy(userType); ExtraFeeStrategy extraFeeStrategy = StrategyFactory.getExtraFeeStrategy(userType); // 2. 应用折扣策略 double discountAmount = discountStrategy.calculateDiscount(productType, originalPrice); double priceAfterDiscount = originalPrice - discountAmount; // 3. 应用费用策略 double extraFee = extraFeeStrategy.calculateExtraFee(productType, priceAfterDiscount); // 4. 返回最终价格 return priceAfterDiscount + extraFee; } }

3. 重构效果对比:从混乱到清晰

我们把新旧两个版本放在一起对比一下,变化一目了然。

对比维度原始版本 (PriceCalculator)重构版本 (RefactoredPriceCalculator)
核心方法行数约40行,包含所有业务逻辑约10行,只负责流程编排
可读性需要仔细阅读嵌套条件才能理解像读说明书:获取策略 -> 计算折扣 -> 计算费用 -> 返回结果
可维护性修改任意规则需深入核心方法,风险高修改规则只需调整对应的策略类,核心流程不动
可测试性难以测试单一场景,需构造复杂参数每个策略类可独立进行单元测试,核心计算器只需Mock策略
扩展性新增类型必须修改核心方法,违反开闭原则新增类型只需增加新的策略类并在工厂注册,符合开闭原则
职责单一一个类负责了折扣计算、费用计算、逻辑分发每个类职责清晰:计算器编排、工厂创建、策略实现

最直观的感受是,阅读重构后的代码,你几乎不需要注释就能明白它在做什么。而原始的代码,即便加上注释,随着后续修改,注释也很容易过时,导致代码重新变得难以理解。

4. 更进一步:使用枚举与注册表优化工厂

上面的工厂使用switch语句,已经不错了。但我们可以再进一步,消除switch,让扩展更加优雅。这里可以引入一个策略注册表的概念。

// 1. 使用枚举定义用户类型 public enum UserType { REGULAR, VIP, INTERNAL } // 2. 策略注册表(这里用Map模拟) public class StrategyRegistry { private static final Map<UserType, DiscountStrategy> discountStrategyMap = new HashMap<>(); private static final Map<UserType, ExtraFeeStrategy> extraFeeStrategyMap = new HashMap<>(); static { // 初始化注册关系 discountStrategyMap.put(UserType.VIP, new VipDiscountStrategy()); discountStrategyMap.put(UserType.INTERNAL, new InternalStaffDiscountStrategy()); discountStrategyMap.put(UserType.REGULAR, new RegularUserDiscountStrategy()); extraFeeStrategyMap.put(UserType.INTERNAL, new InternalStaffFeeStrategy()); extraFeeStrategyMap.put(UserType.VIP, new RegularUserFeeStrategy()); // VIP和普通用户费用策略相同 extraFeeStrategyMap.put(UserType.REGULAR, new RegularUserFeeStrategy()); } public static DiscountStrategy getDiscountStrategy(UserType userType) { return discountStrategyMap.get(userType); } public static ExtraFeeStrategy getExtraFeeStrategy(UserType userType) { return extraFeeStrategyMap.get(userType); } // 允许运行时动态注册新策略(如果需要) public static void registerDiscountStrategy(UserType userType, DiscountStrategy strategy) { discountStrategyMap.put(userType, strategy); } }

然后,计算器和使用方式也变得更类型安全:

public class EnhancedPriceCalculator { public double calculatePrice(UserType userType, String productType, double originalPrice) { DiscountStrategy discountStrategy = StrategyRegistry.getDiscountStrategy(userType); ExtraFeeStrategy extraFeeStrategy = StrategyRegistry.getExtraFeeStrategy(userType); double discountAmount = discountStrategy.calculateDiscount(productType, originalPrice); double priceAfterDiscount = originalPrice - discountAmount; double extraFee = extraFeeStrategy.calculateExtraFee(productType, priceAfterDiscount); return priceAfterDiscount + extraFee; } } // 使用示例 public class Main { public static void main(String[] args) { EnhancedPriceCalculator calculator = new EnhancedPriceCalculator(); double price = calculator.calculatePrice(UserType.VIP, "DISCOUNT", 100.0); System.out.println("Final Price: " + price); // 输出: Final Price: 83.0 } }

这样做的好处是,彻底消除了工厂方法中的switchif-else。新增一种用户类型时,只需创建新的枚举值,并在注册表中绑定对应的策略即可,扩展点非常明确。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.jsqmd.com/news/488840/

相关文章:

  • 计科-软工8-面向对象方法学引论
  • 伏羲模型论文与技术报告编写利器:LaTeX排版实战教程
  • Python气象利器Meteva:从踩坑到定制化绘图的实战指南
  • DeOldify赋能传统文化数字化:古书画、壁画仿真着色应用探索
  • 机器人电机测试系统哪家好?2026机器人关节模组测试设备推荐:杭州威衡科技,机器人电机与关节模组测试解决方案 - 栗子测评
  • 融合视觉与语音:SenseVoice-Small在多模态AI应用中的角色
  • 突破硬件枷锁:Universal x86 Tuning Utility释放x86设备隐藏性能
  • STC32G12K128核心板:高性能8051兼容MCU硬件设计详解
  • 效率提升秘籍:用快马一键生成集成imToken等钱包连接的React样板代码
  • 阿里开源AI绘画神器Z-Image-Turbo:16G显存就能跑,快速上手指南
  • 2026年口碑好的脑波注意力训练系统采购公司推荐:脑波注意力训练系统定制公司精选 - 品牌宣传支持者
  • Qwen3-14B开源模型部署避坑指南:vLLM加载失败与Chainlit响应延迟解决
  • 2026数控无心磨床生产厂家推荐:12S型无心磨床生产厂家+数控高精度无心磨床厂家多家甄选 - 栗子测评
  • 通义千问2.5-7B代码助手实战:帮你写Python脚本、调试程序
  • 2026电机测试系统哪家好?杭州威衡科技-高精度定制+全场景适配,电机测试系统定制公司优选品牌 - 栗子测评
  • 用Qwen3-TTS-12Hz-1.7B-Base打造智能语音客服:完整部署与应用案例
  • 普联TL-IPC669-A4摄像机拆解全记录:从螺丝刀到电路板的完整指南
  • 无人机电机测试系统哪家好?2026科研用电机测试设备推荐:杭州威衡科技,科研级精准赋能+无人机专项适配 - 栗子测评
  • 图信号处理中的多尺度分析:图小波变换与图傅里叶变换的对比与应用
  • Windows 11安装避坑指南:传统BIOS下的ISO文件修改技巧
  • AXI协议深度解析:信号通道与低功耗设计
  • 2026电机产线测试系统哪家好?产线高效测试+高速精准适配+AI故障预警-杭州威衡科技全方位电机测试解决方案 - 栗子测评
  • NVIDIA Profile Inspector全方位指南:从参数调试到专业显卡性能优化
  • 【IEEE】从投稿到录用:IEEE期刊会议全流程实战避坑指南(2024版)
  • IwaraDownloadTool技术指南:高效视频内容获取解决方案
  • 量子传感如何重塑机器人?具身智能的“超感官”革命
  • SiameseAOE中文-base惊艳效果:方言表达‘巴适’‘攒劲’映射至‘满意度’情感维度
  • 工业质检实战:用知识蒸馏(Knowledge Distillation)搞定图像缺陷检测的3个常见坑
  • Phi-3 Forest Laboratory 内存优化教程:解决C盘空间不足与模型加载问题
  • 真的存在这个风险:就是一个AI可能会取代大多数软件