导读:
反 IF 编程方法由 Francesco Cirillo 于 2007 年发起,它改变了许多人对软件设计中的 IF 和条件句的看法。
软件设计的核心是一种简单但潜在危险的工具:条件“IF”语句。不可否认,它的基础性在于,它用于处理增长环境中的变化,被称为“IF 策略”,它可能是一个无声的破坏者,使代码复杂化和逻辑混乱。
IF 策略可能导致调试问题、从未交付的用户故事、技术债务、纠结的设计、团队中的摩擦和其他低效率。
从本质上讲,IF 策略会增加成本并延迟软件交付时间,同时降低内部质量。
有一个传说中古老的遗留系统,我的同事从上到下编码了数千行,每个块都添加了几个 if then java 部分来做路由,我感觉自己被困在一个陌生的仙境中。
在这篇文章中,我将向大家展示如何优化 if-else 的使用,限制具有太多分支条件的代码,并使我们的 Java 代码更易于阅读和理解。
public class ShippingCostCalculator {public double calculateShippingCost(String shippingType, double weight) {if (shippingType.equals("STANDARD")) {return weight * 5.0;} else if (shippingType.equals("EXPRESS")) {return weight * 10.0;} else if (shippingType.equals("SAME_DAY")) {return weight * 20.0;} else if (shippingType.equals("INTERNATIONAL")) {return weight * 50.0;} else if (shippingType.equals("OVERNIGHT")) {return weight * 30.0;}return 0;}}
如各位所见,上面的代码功能是根据快递类型计算运费。
public enum ShippingType {STANDARD {@Overridepublic double getCost(double weight) {return weight * 5.0;}},EXPRESS {@Overridepublic double getCost(double weight) {return weight * 10.0;}},SAME_DAY {@Overridepublic double getCost(double weight) {return weight * 20.0;}},INTERNATIONAL {@Overridepublic double getCost(double weight) {return weight * 50.0;}},OVERNIGHT {@Overridepublic double getCost(double weight) {return weight * 30.0;}};public abstract double getCost(double weight);}
public class ShippingCostCalculator {public double calculateShippingCost(ShippingType shippingType, double weight) {return shippingType.getCost(weight);}}
public class MainCost {public static void main(String[] args) {var calculator = new ShippingCostCalculator();var cost = calculator.calculateShippingCost(ShippingType.EXPRESS, 2.5);System.out.println("Shipping cost: " + cost);}}
可以看到,复杂的 if-else 语句被简化成了两行简短、直接的代码。运行 main 函数,查看结果。
优势:
可扩展性:添加新的运输类型和值。枚举并定义处理方法。
可维护且可理解的代码:每种传输方法的原因都是独立的且易于理解。
然而,使用Enum也有一些明显的缺点,您应该考虑:
可扩展性:添加新的运输类型和值。枚举并定义处理方法。
难以添加新参数:当需要更多参数时,Enum 不太适合,并且代码变得繁琐。
继承限制:Enum不能从其他类继承,这降低了它们重用逻辑的潜力。
使用 Enum 进行优化通常适用于参数较少的简单情况。
创建接口 ShippingCostStrategy
public interface ShippingCostStrategy {double calculate(double weight);}
现在我们将创建一个工厂类来处理基于运输类型的策略路由:
import java.util.HashMap;import java.util.Map;public class ShippingCostFactory {private static final Mapstrategies = new HashMap<>(); static {strategies.put("STANDARD", new StandardShipping());strategies.put("EXPRESS", new ExpressShipping());strategies.put("SAME_DAY", new SameDayShipping());strategies.put("INTERNATIONAL", new InternationalShipping());strategies.put("OVERNIGHT", new OvernightShipping());}public static ShippingCostStrategy getStrategy(String shippingType) {ShippingCostStrategy strategy = strategies.get(shippingType);if (strategy == null) {throw new IllegalArgumentException("Invalid shipping type: " + shippingType);}return strategy;}}
现在只需调用并使用它。
public class ShippingCostCalculator {public double calculateShippingCost(String shippingType, double weight) {ShippingCostStrategy strategy = ShippingCostFactory.getStrategy(shippingType);return strategy.calculate(weight);}}
易于扩展:只需开发附加类并更新工厂即可添加新的交付类型,而无需更改核心代码。
逻辑分离:收费逻辑是独立的,易于管理和维护。
灵活性:工厂可能会根据其他因素返回多个解决方案,从而提高灵活性。
public interface ShippingCostStrategy {double calculate(double weight);}
public class StandardShipping implements ShippingCostStrategy {@Overridepublic double calculate(double weight) {return weight * 5.0;}}public class ExpressShipping implements ShippingCostStrategy {@Overridepublic double calculate(double weight) {return weight * 10.0;}}public class SameDayShipping implements ShippingCostStrategy {@Overridepublic double calculate(double weight) {return weight * 20.0;}}public class InternationalShipping implements ShippingCostStrategy {@Overridepublic double calculate(double weight) {return weight * 50.0;}}public class OvernightShipping implements ShippingCostStrategy {@Overridepublic double calculate(double weight) {return weight * 30.0;}}
现在我们将创建 ShippingContext 来管理策略。
public class ShippingCostContext {private ShippingCostStrategy strategy;public void setStrategy(ShippingCostStrategy strategy) {this.strategy = strategy;}public double calculateShippingCost(double weight) {return strategy.calculate(weight);}}
import java.util.HashMap;import java.util.Map;public class ShippingCostCalculator {private static final Mapstrategies = new HashMap<>(); static {strategies.put("STANDARD", new StandardShipping());strategies.put("EXPRESS", new ExpressShipping());strategies.put("SAME_DAY", new SameDayShipping());strategies.put("INTERNATIONAL", new InternationalShipping());strategies.put("OVERNIGHT", new OvernightShipping());}private final ShippingCostContext context = new ShippingCostContext();public double calculateShippingCost(String shippingType, double weight) {ShippingCostStrategy strategy = strategies.get(shippingType);if (strategy == null) {throw new IllegalArgumentException("Invalid shipping type: " + shippingType);}context.setStrategy(strategy);return context.calculateShippingCost(weight);}}
现在,把它放进主类里面使用。
public class MainCost {public static void main(String[] args)ShippingCostCalculator calculator = new ShippingCostCalculator();double weight = 10.0;String shippingType1 = "STANDARD";double cost1 = calculator.calculateShippingCost(shippingType1, weight);System.out.println("Shipping cost for " + shippingType1 + ": " + cost1);String shippingType2 = "EXPRESS";double cost2 = calculator.calculateShippingCost(shippingType2, weight);System.out.println("Shipping cost for " + shippingType2 + ": " + cost2);String shippingType3 = "SAME_DAY";double cost3 = calculator.calculateShippingCost(shippingType3, weight);System.out.println("Shipping cost for " + shippingType3 + ": " + cost3);String shippingType4 = "INTERNATIONAL";double cost4 = calculator.calculateShippingCost(shippingType4, weight);System.out.println("Shipping cost for " + shippingType4 + ": " + cost4);String shippingType5 = "OVERNIGHT";double cost5 = calculator.calculateShippingCost(shippingType5, weight);System.out.println("Shipping cost for " + shippingType5 + ": " + cost5);}}
在前两种情况下,策略模式管理如何计算运输成本,而工厂模式根据运输类型决定采用哪种策略。
import java.util.HashMap;import java.util.Map;public class ShippingCostCalculator {private static final MapshippingCosts = new HashMap<>(); static {shippingCosts.put("STANDARD", 5.0);shippingCosts.put("EXPRESS", 10.0);shippingCosts.put("SAME_DAY", 20.0);shippingCosts.put("INTERNATIONAL", 50.0);shippingCosts.put("OVERNIGHT", 30.0);}public double calculateShippingCost(String shippingType, double weight) {return shippingCosts.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase(shippingType)).map(Map.Entry::getValue).findFirst().orElse(0.0)* weight;}public static void main(String[] args) {ShippingCostCalculator calculator = new ShippingCostCalculator();double weight = 10.0;String shippingType1 = "STANDARD";double cost1 = calculator.calculateShippingCost(shippingType1, weight);System.out.println("Shipping cost for " + shippingType1 + ": " + cost1);String shippingType2 = "EXPRESS";double cost2 = calculator.calculateShippingCost(shippingType2, weight);System.out.println("Shipping cost for " + shippingType2 + ": " + cost2);String shippingType3 = "SAME_DAY";double cost3 = calculator.calculateShippingCost(shippingType3, weight);System.out.println("Shipping cost for " + shippingType3 + ": " + cost3);String shippingType4 = "INTERNATIONAL";double cost4 = calculator.calculateShippingCost(shippingType4, weight);System.out.println("Shipping cost for " + shippingType4 + ": " + cost4);String shippingType5 = "OVERNIGHT";double cost5 = calculator.calculateShippingCost(shippingType5, weight);System.out.println("Shipping cost for " + shippingType5 + ": " + cost5);String invalidType = "INVALID";double invalidCost = calculator.calculateShippingCost(invalidType, weight);System.out.println("Shipping cost for " + invalidType + ": " + invalidCost);}}
这个策略也比较方便,虽然扩展性不如Factory和Strategy,但对于简单的场景来说还是一个可行的选择。
谢谢大家,在您离开之前:
👏 请为文章点赞或转发 👉
也欢迎在下面的评论部分分享您的问题或见解。
本文最初于 2024 年 8 月 20 日发布于https://cafeincode.com。
作者:陈兴
本篇文章为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。