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

对象缓存技术:避免重复调用耗时方法的实现方案

可行解决方案

以下是几种避免重复调用longRunningMethod的方案,同时解决直接传int参数含义不明确的问题:

方案1:在C类内部添加结果缓存

直接在C类中对longRunningMethod的结果进行缓存,确保方法仅执行一次,后续调用直接返回缓存值。适合该方法的结果在C实例生命周期内不会变化的场景。

public class C {
    private Integer cachedResult; // 用Integer区分未初始化和结果为0的情况

    public int longRunningMethod() {
        if (cachedResult == null) {
            // 执行原耗时逻辑
            cachedResult = doLongRunningCalculation();
        }
        return cachedResult;
    }

    // 把原耗时逻辑抽离,让缓存逻辑更清晰
    private int doLongRunningCalculation() {
        ...
    }
}

说明:无需修改A、B和MyProgram的代码(仅需修正B类构造函数的笔误,将public A(C c)改为public B(C c)),调用逻辑完全不变,但longRunningMethod只会执行一次。如果后续需要刷新结果,可以新增resetCache()方法清除缓存。

方案2:封装结果为有意义的业务对象

将longRunningMethod的结果封装成一个具有明确业务含义的对象,替代直接传递int,既解决参数含义模糊的问题,又能确保结果只计算一次。

// 根据实际业务场景命名,比如"TaskExecutionResult"、"CalculatedMetric"
public class CalculatedTaskResult {
    private final int value;

    public CalculatedTaskResult(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

// 修改A类,依赖业务对象而非C
public class A {
    private final CalculatedTaskResult result;

    public A(CalculatedTaskResult result) {
        this.result = result;
    }

    public void method1() {
        int value = result.getValue();
        // 原业务逻辑
        ...
    }
}

// 修改B类,同理
public class B {
    private final CalculatedTaskResult result;

    public B(CalculatedTaskResult result) {
        this.result = result;
    }

    public void method2() {
        int value = result.getValue();
        // 原业务逻辑
        ...
    }
}

// MyProgram中仅调用一次耗时方法
public class MyProgram {
    public static void main(String[] args) {
        C c = new C();
        CalculatedTaskResult result = new CalculatedTaskResult(c.longRunningMethod());
        A a = new A(result);
        B b = new B(result);
        a.method1();
        b.method2(); // 无需再调用C的耗时方法
    }
}

说明:通过业务对象明确参数含义,同时将计算逻辑集中在入口处,避免重复调用。如果A、B仍需要使用C的其他方法,可以同时注入C和CalculatedTaskResult。

方案3:使用代理类缓存结果

给C定义接口,创建代理类封装缓存逻辑,A、B依赖接口而非具体实现,通过代理确保方法仅执行一次。这种方式符合依赖倒置原则,扩展性更好。

// 定义C的接口,抽象核心方法
public interface CService {
    int longRunningMethod();
}

// 原C类实现接口
public class C implements CService {
    @Override
    public int longRunningMethod() {
        // 原耗时逻辑
        ...
    }
}

// 代理类,专门处理缓存逻辑
public class CServiceProxy implements CService {
    private final CService target;
    private Integer cachedResult;

    public CServiceProxy(CService target) {
        this.target = target;
    }

    @Override
    public int longRunningMethod() {
        if (cachedResult == null) {
            cachedResult = target.longRunningMethod();
        }
        return cachedResult;
    }
}

// MyProgram中注入代理对象
public class MyProgram {
    public static void main(String[] args) {
        CService c = new CServiceProxy(new C());
        A a = new A(c);
        B b = new B(c);
        a.method1(); // 首次调用执行耗时逻辑
        b.method2(); // 后续调用直接返回缓存结果
    }
}

说明:代理类隔离了缓存逻辑,原C类无需修改,A、B的代码也无需变动。如果后续需要更换缓存策略(比如超时自动刷新),只需修改代理类即可。

方案4:让A和B共享结果持有者

创建一个结果持有者类,负责管理C的计算结果,A、B依赖该持有者,由持有者确保仅调用一次longRunningMethod。

public class CResultHolder {
    private final C c;
    private Integer cachedResult;

    public CResultHolder(C c) {
        this.c = c;
    }

    public int getLongRunningResult() {
        if (cachedResult == null) {
            cachedResult = c.longRunningMethod();
        }
        return cachedResult;
    }

    // 如果需要使用C的其他方法,可以暴露getter
    public C getC() {
        return c;
    }
}

// 修改A类
public class A {
    private final CResultHolder resultHolder;

    public A(CResultHolder resultHolder) {
        this.resultHolder = resultHolder;
    }

    public void method1() {
        int value = resultHolder.getLongRunningResult();
        // 原业务逻辑
        ...
    }
}

// 修改B类同理
public class B {
    private final CResultHolder resultHolder;

    public B(CResultHolder resultHolder) {
        this.resultHolder = resultHolder;
    }

    public void method2() {
        int value = resultHolder.getLongRunningResult();
        // 原业务逻辑
        ...
    }
}

// MyProgram中初始化持有者
public class MyProgram {
    public static void main(String[] args) {
        C c = new C();
        CResultHolder holder = new CResultHolder(c);
        A a = new A(holder);
        B b = new B(holder);
        a.method1();
        b.method2();
    }
}

说明:持有者类专门负责结果的缓存和获取,A、B无需关心计算逻辑,只需从持有者拿结果。如果A、B还需要使用C的其他方法,可以通过持有者的getC()方法获取实例。


内容的提问来源于stack exchange,提问作者peer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:30:44