首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在使用装饰器模式时,如何保留接口?

在使用装饰器模式时,如何保留接口?
EN

Stack Overflow用户
提问于 2011-05-14 08:47:10
回答 3查看 521关注 0票数 1

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

代码语言:javascript
复制
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实例化了D的实例,它可能是C1、C2或C3,我们就失去了对包装的I可能实现的I1、I2、I3和I4的附加方法的访问权。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-05-14 17:13:26

如果C1、C2、C3是接口,那么就会有一个代理解决方案。

代码语言:javascript
复制
interface C1 extends I, I1, I2

否则,您将需要一个像cglib这样的库来装饰这个类。

代理与泛型工厂方法相结合将保留其他接口,因此您不需要在代码中进行强制转换:

代码语言:javascript
复制
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
}

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

代码语言:javascript
复制
C1 c1 = ...;
c1 = D.decorate(c1);
票数 1
EN

Stack Overflow用户

发布于 2011-05-14 09:17:13

界面应该是这样的。

代码语言:javascript
复制
interface I
{
   I objI {get;} // can hold reference to other objects of type I or null
   // If the requirement is to make setter as public, that should be fine as well.

   // You can have decorator related behavior here
   void DecoratorBehavior1(); 
   void DecoratorBehavior2(); 
}

类D不需要执行包装。它所做的是实现I。

代码语言:javascript
复制
class D implements I
{
  public I objI {get; private set;}
  // You can have other overloaded constructors as well
  D(I obj)
  {
     this.objI = obj;
  }
}

I类型的对象包含对I类型或null类型的其他对象的引用。此对象可以实现其他类型的接口,也可以从其他基类派生。

如果要使用其他类型的方法,可以将对象类型转换为相应的类型并使用。在进行类型转换之前,您可以验证对象是否确实属于某个类型。

代码语言:javascript
复制
....
I objC1 = new C1(null);
I objC2 = new C2(objC1);
I objC3 = new C3(objC2);
I objD = new D(objC3);
...
I oGetBackC3 = objD.objI;
if(oGetBackC3 is typeof(C3))
{
   C3 oGotBackC3 = (C3)oGetBackC3;
   ...
   // You can now call C3 methods on object
}
....

我已经用C#编写了代码片段,但它可能仍然适用于Java。

票数 0
EN

Stack Overflow用户

发布于 2011-05-14 16:27:06

您可以使用Proxy.newProxy()作为装饰器。您可以为它提供一个要实现的接口列表,并且您可以编程地包含和处理任意数量的接口,如果您愿意,还可以添加一些您自己的接口。唯一不能做的事情就是让代理扩展一个给定的类。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5999122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档