具有最终方法的Java类装饰器

时间:2012-08-02 09:38:12

标签: java decorator final

我有一个(Java)类WindowItem,它有一个问题:其中一个方法不是线程安全的。我无法修复WindowItem,因为它是外部框架的一部分。所以我想我为它实现了一个Decorator,它在所讨论的方法上有一个“synchronized”关键字。

Decorator扩展了WindowItem,并且还包含WindowItem。在Decorator模式之后,我在Decorator中创建了调用它包含的WindowItem的方法。

但是,WindowItem有一些最终方法,我无法在Decorator中覆盖。这打破了装饰者的透明度。让我们明确这一点:

public class WindowItem {
   private List<WindowItem> windows;

   public Properties getMethodWithProblem() {
      ...
   }

   public final int getwindowCount() {
      return windows.size();
  }
}

public class WindowItemDecorator extends WindowItem {
   private WindowItem item;

   public WindowItemDecorator(WindowItem item) {
      this.item = item;
   }

   # Here I solve the problem by adding the synchronized keyword:
   public synchronized Properties getgetMethodWithProblem() {
      return super.getMethodWithProblem();
   }

   # Here I should override getWindowCount() but I can't because it's final
}

在我自己的代码中,每当我必须在某处传递一个WindowItem时,我首先将它包装在装饰器中:new WindowItemDecorator(item) - 并且线程安全问题消失了。但是,如果我的代码在WindowItemDecorator上调用getwindowCount(),它将始终为零:它在超类而不是“item”成员上执行getWindowCount()。

所以我想说WindowItem的设计(事实上它有公共最终方法)使得无法为这个类创建一个Decorator。

这是正确的,还是我错过了什么?

在这种情况下,我可以在装饰器中保留窗口列表的副本,并使其保持同步,然后getWindowCount()的结果将是正确的。但在这种情况下,我更喜欢分叉和修补框架......

4 个答案:

答案 0 :(得分:1)

也许您可以使用Delegation Pattern,如果WindowItem类实现了一个定义您关注的所有方法的接口,那么这将很好地工作。或者,如果它不会过多地破坏现有代码来引用此委派类而不是WindowItem

答案 1 :(得分:1)

怎么不以这种方式思考问题?为什么不在代码中处理线程问题,而不假设WindowItem的线程安全性。

// I personally prefer ReadWriteLocks, but this sounds like it will do...
synchronized (windowItem) {
    windowItem.getMethodWithProblem();
}

然后使用软件包维护者提交RFE以更好地支持线程安全。

实际上,如果该类不是设计为线程安全的,那么一些synchronized关键字不太可能真正解决问题。某人通过“线程安全”的意思总是相对的; - )

(顺便说一句,WindowItem肯定是 NOT 线程安全,因为它使用List而不是明确使用“线程就绪”变体Correct way to synchronize ArrayList in java - 有也不能保证以线程安全的方式访问List

答案 2 :(得分:0)

您的问题的答案是肯定的,您无法覆盖最终方法,这意味着无法为此类创建装饰器。

如果你可以覆盖有问题的方法,并通过同步方法解决问题,你可以保留它。也就是说,只使用你的子类,而不是使用装饰器模式。

答案 3 :(得分:-1)

一位同事认为我认为可以解决这个问题。通过查看修改List窗口的所有方法,我可以保持超类的状态和“item”成员的状态同步。有几个:addWindow,removeWindow。我没有在装饰器中调用“item.addWindow(...)”,而是在超类上调用addWindow:

普通装饰者:

public void addWindow(WindowItem newItem) {
   item.addWindow(newItem);
}

在这种情况下,我这样做:

public void addWindow(WindowItem newItem) {
   super.addWindow(newItem);
   item.addWindow(newItem);
}

这使状态保持同步,最终方法的返回值也正确。

这是一个可以工作或不工作的解决方案,具体取决于正在修饰的类的内部。