You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:44:27