【问题标题】:create a wrapper class with additional features in java在 java 中创建一个具有附加功能的包装类
【发布时间】:2020-11-25 18:02:32
【问题描述】:

我想在另一个类上创建一个包装器类,以便它隐藏被包装类的功能,并且包装器提供自己的某些方法。

例如,假设我们有 A 类

public class A{
    void method1(){ ... do something ... }
    void method2(){ ... do something ... }
    void method3(){ ... do something ... }
}

现在我想要另一个包装类A的B类,这样它就有自己的方法,而且如果有人问A类的方法,它应该把它委托给A类。

public class B{
     // if someone asks method1() or method2() or method3() ... it should delegate it to A
     
     // and also it has own methods
     void method4(){ ... do something ... }
     void method5(){ ... do something ... }
}

我不能使用继承(即 B 扩展 A),因为它在我的用例中并不容易(其中 A 具有带有一些我们无法获得的参数的具体构造函数......但我们可以获得 A 的对象) .

我不能简单地使用 A 的对象来委托 A 中的每个函数(因为 A 中有几个函数)

有没有其他方法可以获得具有上述限制的B级?

重要提示: A 类由其他人处理。我们不能改变它的任何部分。

【问题讨论】:

  • 也许,反射是你唯一的选择。你确定不能委托这些方法吗?
  • 你能更好地解释为什么“我不能简单地使用 A 的对象委托 A 中的每个函数(因为 A 中有几个函数)”?
  • A类可以是单例还是需要多重继承?
  • @bakero98 类 A 继承自包含多个方法的单个接口。 A类不需要是单例的
  • 您的要求“......因此它隐藏了包装类的功能”与您想要为 A 的每个方法创建一个委托方法,甚至反映 A 的潜在变化的事实之间存在矛盾API。换句话说,你不是隐藏而是暴露 A 的每一个功能。你不能少封装。那么为什么不直接向B 添加一个返回A 的方法就完成了。您的伪封装只会浪费开发工作而没有任何好处。

标签: java reflection wrapper delegation dynamic-proxy


【解决方案1】:

这可以通过 CGLIB 轻松完成,但只需少量修改。考虑这些修改是否比方法的实际委派更难。

  1. 你需要扩展类,这可以通过向类 A 添加无参数构造函数来完成,我们仍然会委托所有方法,所以不要担心无法访问的参数,我们不担心丢失数据,我们只是想要方法

  2. 你需要在你的类路径 cglib maven 上拥有 CGLIB,也许你已经拥有它了

A 看起来像

public class A {

    private String arg = "test";

    public A() {
        // noop just for extension
    }

    public A(String arg) {
        this.arg = arg;
    }

    public void method1() {
        System.out.println(arg);
    }
}

B 看起来像

public class B extends A implements MethodInterceptor {

    private A delegate;

    private B(A delegate) {
        this.delegate = delegate;
    }

    public static B createProxy(A obj) {
        Enhancer e = new Enhancer();
        e.setSuperclass(obj.getClass());
        e.setCallback(new B(obj));
        B proxifiedObj = (B) e.create();
        return proxifiedObj;
    }

    void method2() {
        System.out.println("a");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) { return m.invoke(this, objects); }
        Object res = method.invoke(delegate, objects);
        return res;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}

你能做到的

MyInterface b = B.createProxy(new A("delegated"));
b.method1(); // will print delegated

这不是很好的解决方案,您可能不需要它,请在执行此操作之前考虑重构您的代码。这应该只在非常特殊的情况下使用。

【讨论】:

  • 感谢这种方法。我忘了提到我们不能修改 A 类中的任何内容(由其他人处理)。但是您的方法似乎很好,因为我们在 A 中添加了默认构造函数。但是在不更改 A 类中的任何内容的情况下,我们可以解决在 B 中委派 A 方法的问题吗?
  • 您需要自己实现所有方法。所以我的猜测是否定的,如果你不能改变 A 中的任何东西。
【解决方案2】:

您所描述的是 GOF 创造的装饰器模式。互联网上有很多关于它的资源。它类似于代理模式(如 Pavel Polivka 的回答),但意图不同。你需要装饰器模式:

动态地为对象附加额外的职责。装饰器为扩展功能提供了一种灵活的替代子类的方法。 sourcemaking.com

正如您在评论中所写的那样

类 A 继承自包含多个方法的单个接口

我假设A implements AIntf 并包含你想要的所有方法。

public class BDecorator implements AIntf {
    private A delegate;

    private BDecorator(A delegate) {
        this.delegate = delegate;
    }

    void method1(){ delegate.method1(); }
    // ...

    void method4(){ /* something new */ }

A 中有几个函数,我不想在 B 中显式编写每个方法的繁琐工作。

Java 是一种冗长的语言。但是,您不需要手动执行此操作,每个体面的 IDE 都提供了委托方法的自动生成。因此,任何数量的方法都需要 5 秒。

A 类不在我的控制范围内,我的意思是有人可能会更新它的方法签名,在这种情况下,我需要监视 A 类并更改我的 B 类。

如果你创建了 B,你就要对它负责。您至少会注意到是否有任何变化。再一次,您可以在 IDE 的帮助下立即重新生成更改后的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-19
    • 2014-08-09
    • 1970-01-01
    • 2017-06-18
    • 2017-02-23
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多