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

发布于 2024-11-07 12:00:42 字数 360 浏览 0 评论 0原文

如果被装饰的对象实现了其他接口的不同组合,那么如何在不丢失额外接口方法的情况下实现装饰器呢?例如,假设我们有以下类和接口,其中 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 实例化 D 的实例,可能是 C1、C2,或 C3,我们将无法访问包装 I 可能实现的 I1、I2、I3 和 I4 的附加方法。

If the objects being decorated implement different combinations of other interfaces, how do you implement a decorator without losing the extra interface methods? For example, say we have the following classes and interfaces, where I is the one we care about for decorating and D is the implementation of a decorator:

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
}

Once we instantiate an instance of D with a wrapped I, which may be C1, C2, or C3, we lose access to the additional methods for I1, I2, I3, and I4 that the wrapped I may implement.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

幽梦紫曦~ 2024-11-14 12:00:42

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

interface C1 extends I, I1, I2

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

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

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);

If C1, C2, C3 would be interfaces there will be a proxy solution.

interface C1 extends I, I1, I2

Else you would need a library like cglib to decorate the class.

A proxy in combination with a generic factory method will preserve the other interfaces so you need no cast in the code:

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
}

Now you can use it the following way:

C1 c1 = ...;
c1 = D.decorate(c1);
坏尐絯℡ 2024-11-14 12:00:42

界面会是这样的。

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。

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 的其他对象的引用。该对象可以实现其他类型的接口,或者可以从其他基类派生。

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

....
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 来说也可能保持不变。

The interface would be something like this.

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(); 
}

class D need not perform wrapping. What it does is implement I.

class D implements I
{
  public I objI {get; private set;}
  // You can have other overloaded constructors as well
  D(I obj)
  {
     this.objI = obj;
  }
}

Object of type I holds a reference to other object of type I or null. This object may implement interfaces of other types or may be derived from other base classes.

If you want to use methods of other types, you can typecast the object to respective type and use. Before typecasting you can verify if the object is indeed of a certain type or not.

....
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
}
....

I have written snippet in C#, but it may remain same for Java as well.

与之呼应 2024-11-14 12:00:42

您可以使用 Proxy.newProxy() 作为装饰器。您给它一个要实现的接口列表,您可以以编程方式包含和处理任意数量的接口,并根据需要添加一些您自己的接口。您唯一不能做的就是让代理扩展给定的类。

You can use Proxy.newProxy() as the decorator. You give it a list of interfaces to implement and you can programatically include and handle any number of interfaces and add a few of your own if you wish. The only thing you can't do is have the Proxy extend a given class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文