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

Java装饰器模式能否访问辅助方法?场景实现疑问

问题描述

现有一个旗帜接口flag,包含wave()和辅助方法calculateWind()。实现类flagImpl的wave()会调用自身的calculateWind();装饰类decoratedFlag对两个方法都做了装饰,但执行代码后仅输出this is decorated,装饰后的calculateWind()从未被触发。

需要解决:能否让flagImpl调用已实例化的装饰器对象的calculateWind()而非自身的?或者装饰器模式下有没有通用解决思路?

代码示例(修正原代码递归错误):

public class Main {
    public static void main(String[] args) {
        flag flag = new decoratedFlag(new flagImpl());
        flag.wave();
    }
}

public interface flag {
    int wave();
    int calculateWind();
}

public class flagImpl implements flag {
    @Override
    public int wave() {
        return calculateWind();
    }

    @Override
    public int calculateWind() {
        return 8;
    }
}

public class decoratedFlag implements flag {
    private flag flag;

    public decoratedFlag(flag flag) {
        this.flag = flag;
    }

    @Override
    public int wave() {
        System.out.println("this is decorated");
        return flag.wave();
    }

    @Override
    public int calculateWind() {
        System.out.println("this is ALSO decorated");
        return flag.calculateWind();
    }
}
解决思路与方案

核心问题是:flagImpl的wave()直接调用自身calculateWind()时,this指向自身而非外层装饰器,导致装饰逻辑无法介入。以下是两种可行方案:

方案1:重构实现类,注入方法依赖

修改flagImpl,让它不再硬编码调用自身方法,而是通过构造函数传入一个flag类型的依赖,让装饰器可以把自身注入进去,从而让flagImpl调用装饰器的calculateWind()。

示例代码:

public class flagImpl implements flag {
    private flag windCalculator;

    // 无参构造保持兼容,默认使用自身逻辑
    public flagImpl() {
        this.windCalculator = this;
    }

    // 带参构造,允许注入外部的方法提供者
    public flagImpl(flag windCalculator) {
        this.windCalculator = windCalculator;
    }

    @Override
    public int wave() {
        return windCalculator.calculateWind(); // 调用注入对象的方法
    }

    @Override
    public int calculateWind() {
        return 8;
    }
}

// 装饰器使用时,将自身传入flagImpl
public class Main {
    public static void main(String[] args) {
        decoratedFlag decorator = new decoratedFlag(null);
        flag flag = new decoratedFlag(new flagImpl(decorator));
        flag.wave();
    }
}

public class decoratedFlag implements flag {
    private flag flag;

    public decoratedFlag(flag flag) {
        this.flag = flag;
    }

    @Override
    public int wave() {
        System.out.println("this is decorated");
        return flag.wave();
    }

    @Override
    public int calculateWind() {
        System.out.println("this is ALSO decorated");
        return 8; // 可根据需求选择是否调用原对象方法
    }
}

方案2:动态代理(通用装饰方案)

如果不想修改原有flagImpl代码,可使用动态代理拦截所有接口方法调用——包括实现类内部的方法调用,确保所有通过接口的操作都经过装饰逻辑。

示例代码(基于JDK动态代理):

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicFlagDecorator implements InvocationHandler {
    private flag target;

    private DynamicFlagDecorator(flag target) {
        this.target = target;
    }

    public static flag decorate(flag target) {
        return (flag) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{flag.class},
                new DynamicFlagDecorator(target)
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行装饰逻辑
        if (method.getName().equals("wave")) {
            System.out.println("this is decorated");
        } else if (method.getName().equals("calculateWind")) {
            System.out.println("this is ALSO decorated");
        }
        // 调用目标方法,确保内部接口方法调用走代理
        return method.invoke(target, args);
    }
}

// 使用方式
public class Main {
    public static void main(String[] args) {
        flag flag = DynamicFlagDecorator.decorate(new flagImpl());
        flag.wave();
    }
}

这种方式无需修改原有实现类,只要接口定义了所有需要装饰的方法,就能覆盖所有调用场景。

装饰器模式通用注意点

  • 默认情况下,被装饰对象内部的方法调用不会经过装饰器,因为this指向自身而非装饰器;
  • 要让内部调用被装饰,要么通过依赖注入转移方法调用控制权,要么用动态代理拦截所有接口方法;
  • 确保所有需要装饰的方法都定义在接口中,否则非接口方法的内部调用无法被拦截。

内容的提问来源于stack exchange,提问作者Rasmus Hjorth Lüdeking

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:35:22