Decorator for Java class with final methods

I have a (Java) WindowItem class that has a problem: one of the methods is not thread safe. I cannot fix WindowItem because it is part of the external structure. Therefore, I decided that I would implement a Decorator for it, which has a "synchronized" keyword in the method in question.

The decorator extends WindowItem and will also contain WindowItem. Following the Decorator drawing, I create methods in Decorator that invoke the WindowItem contained in it.

However, WindowItem has several final methods that I cannot override in Decorator. This violates the transparency of the Decorator. Let's make it explicit:

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

In my own code, whenever I have to skip WindowItem somewhere, I first wrapped it in a decorator: a new WindowItemDecorator (item) - and the thread safety issue will disappear. However, if my code calls getwindowCount () in WindowItemDecorator, it will always be zero: it executes getWindowCount () in the superclass, and not in the "item" element.

So, I would say that the design of WindowItem (the fact that it has public final methods) makes it impossible to create a Decorator for this class.

Is this right, or am I missing something?

In this case, I could save a copy of the window list in the decorator and keep it in sync, and then the result of getWindowCount () would be correct. But in this case, I prefer to develop and fix the framework ...

+4
source share
4 answers

Perhaps you could use a “Delegation Pattern” that would work well if the WindowItem class implements an interface that defines all the methods that you are interested in, Or if it doesn't break your existing code too much to refer to this delegated class, and not on WindowItem .

+1
source

How about not thinking about the problem this way? Why not just handle WindowItem problems in your code without assuming WindowItem thread WindowItem .

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

And then file the RFE with the package maintainer to better maintain thread safety.

Indeed, if the class is not designed for thread safety, it is unlikely that several synchronized keywords will actually correct the situation. What someone means by “safe flow” is always relative; -)

(By the way, WindowItem definitely not thread safe, because it uses List instead of explicitly using the "ready stream" option. The correct way to synchronize ArrayList in java is also no guarantee that List accessed in streaming mode).

+1
source

The answer to your question: yes, you cannot override the final methods, which means that it is impossible to create this decorator for this class.

If you can override a method that has a problem and solve the problem by synchronizing the method, you can simply leave it to that. That is, just use your subclass and do not use the decorator template.

0
source

My colleague had the idea that, I think, it is possible to solve the problem. I can keep the state of the superclass and the state of the element "element" in sync by looking at all the methods that change the list box. There are several: addWindow, removeWindow. Instead of calling only "item.addWindow (...)" in the decorator, I also call addWindow on the superclass:

Normal decorator:

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

In this case, I:

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

This synchronizes the state and returns the correct values ​​of the final methods.

This is a solution that may or may not work depending on the internal components of the class that is issued.

-1
source

All Articles