java - 使用装饰器模式时如何保留接口(interface)?

标签 java design-patterns inheritance casting decorator

如果被装饰的对象实现了其他接口(interface)的不同组合,如何在不丢失额外接口(interface)方法的情况下实现装饰器?例如,假设我们有以下类和接口(interface),其中 I 是我们关心的装饰器,D 是装饰器的实现:

class C1 implements I, I1, I2

class C2 implements I, I2, I3

class C3 implements I, I3, I4

class D implements I {
    I wrappedValue
    // Methods for I
}

一旦我们用包装的 I(可能是 C1、C2 或 C3)实例化 D 的实例,我们就无法访问包装的 I 可能实现的 I1、I2、I3 和 I4 的其他方法。

最佳答案

如果 C1、C2、C3 是接口(interface),就会有代理解决方案。

interface C1 extends I, I1, I2

否则你需要一个像 cglib 这样的库装饰类(class)。

代理与通用工厂方法相结合将保留其他接口(interface),因此您无需在代码中进行强制转换:

class D<T_I extends I> implements InvocationHandler, I {

  public static <T_I extends I> T_I decorate(T_I wrappedValue) {
    return (T_I)Proxy.newProxyInstance(
        wrappedValue.getClass().getClassLoader(),
        getAllInterfaces(wrappedValue.getClass()),
        new D<T_I>(wrappedValue));
  }

  private static Class[] getAllInterfaces(Class type) {
    if (type.isInterface()) {
      Class[] all = new Class[type.getInterfaces().length + 1];
      int i = 0;
      all[i++] = type;
      for (Class t : type.getInterfaces()) {
        all[i++] = t;
      }
      return all;
    } else {
      return type.getInterfaces();
    }
  }


  private final T_I wrappedValue;

  private D(T_I wrappedValue) {
    this.wrappedValue = wrappedValue;
  }

  public Object invoke(Object proxy, Method method, Object[] args) {
    if (method.getDeclaringClass() == I.class) {
      // call wrapped method in D
      return method.invoke(this, args);
    }
    //call unwrapped method of other interface
    return methos.invoke(wrappedValue, args);
  }

  // Methods for I
}

现在您可以通过以下方式使用它:

C1 c1 = ...;
c1 = D.decorate(c1);

关于java - 使用装饰器模式时如何保留接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5999122/

相关文章:

Java整数数学从0-4连续循环

python - 处理文本文件的通用算法/模式

java - 使用 spring 和 Hibernate 的基本 CRUD 应用程序

c++ - 继承 vector 和初始化

Java - 如何将 PDF 打印到特定打印机?

Java从数据库错误将数据设置到JTable

java - 服务层中的验证(Spring Boot)

scala - 案例类继承有什么*如此*错误?

c# - 如果一个类正在使用一个接口(interface),它必须

java - 如何以新值退出 while 循环?