Java 8策略模式实现优化咨询:默认方法存策略是否合理?
关于Java 8策略模式实现的疑问解答
先回答你的第一个问题:把策略函数放在接口默认方法里是正确的实现吗?
答案是可行,但不算最优雅。这种方式确实利用了Java 8的默认方法特性,让你可以在接口中提供策略的具体实现,同时结合Function函数式接口完成了策略模式的核心——将算法(票价计算逻辑)与使用算法的类(ServiceImpl)解耦。
不过这种方式存在几个小问题:
- 每个策略对应一个独立接口,有点冗余。比如
ReclinerTicketStrategy和VipTicketStrategy本质上只是提供了一个Function实例,单独定义接口显得有点“小题大做”,违背了接口的单一职责原则(接口应该定义契约,而非存放具体实现)。 - 策略的复用性和可管理性较差。如果后续新增更多票种策略,你得不断创建新的接口,会导致类爆炸。
更优的实现方案推荐
根据你的场景(固定的几种票价计算策略),这里有几种更简洁、易维护的方案:
方案1:用枚举类统一管理所有策略
枚举天然适合存放固定的、有限的策略实现,代码更集中,管理更方便:
package Java8.controller; import java.util.function.Function; public enum TicketStrategy { RECLINER(quantity -> quantity * 200.00), VIP(quantity -> quantity * 400.00); private final Function<Integer, Double> calculateFunction; TicketStrategy(Function<Integer, Double> calculateFunction) { this.calculateFunction = calculateFunction; } public Function<Integer, Double> getCalculateFunction() { return calculateFunction; } }
使用方式也很简单:
package Java8.controller; public class Main { public Main(){ // 使用躺椅票策略 ITicket reclinerTicket = new ServiceImpl(TicketStrategy.RECLINER.getCalculateFunction()); System.out.println(reclinerTicket.calculateFare(5)); // 输出1000.0 // 使用VIP票策略 ITicket vipTicket = new ServiceImpl(TicketStrategy.VIP.getCalculateFunction()); System.out.println(vipTicket.calculateFare(5)); // 输出2000.0 } public static void main(String args[]){ new Main(); } }
方案2:用工具类存放静态策略方法
如果策略可能需要动态扩展(后续可能新增更多策略,且不想修改原有代码),可以把策略放在工具类中:
package Java8.controller; import java.util.function.Function; public class TicketStrategies { private TicketStrategies() {} // 私有构造,防止实例化 public static Function<Integer, Double> reclinerTicket() { return quantity -> quantity * 200.00; } public static Function<Integer, Double> vipTicket() { return quantity -> quantity * 400.00; } // 后续新增策略直接加静态方法即可 public static Function<Integer, Double> studentTicket() { return quantity -> quantity * 100.00; } }
使用方式:
ITicket studentTicket = new ServiceImpl(TicketStrategies.studentTicket());
方案3:直接传递Lambda表达式(最简洁)
如果策略逻辑很简单,甚至不需要额外的类/接口,直接在使用时传递Lambda即可:
public class Main { public Main(){ // 躺椅票策略 ITicket reclinerTicket = new ServiceImpl(q -> q * 200.00); // VIP票策略 ITicket vipTicket = new ServiceImpl(q -> q * 400.00); } }
这种方式适合策略逻辑简单、且不需要复用的场景,代码最精简。
总结
你的原始实现是正确的,但可以根据实际场景选择更优的方案:
- 如果策略是固定的、数量不多:优先选枚举类方案,集中管理,可读性高。
- 如果策略需要频繁扩展:选工具类方案,新增策略无需修改原有代码,符合开闭原则。
- 如果策略逻辑简单且无需复用:直接用Lambda表达式,最简洁。
内容的提问来源于stack exchange,提问作者CodeMaster
相关产品推荐
相关产品推荐

