I recently took a look at the javadoc for java.awt.Component, and I was rather amazed at its size. It is incredible. I cannot see how it can be proven correct no matter how many unit tests one would write for it. Its cohesion cannot be very good! I tried to make a list of the public non-deprecated methods, and I identified at least 14 different concepts and responsibilities that it deals with (see Appendix A below).
There are a number of heuristics that I think it violates (I happened to choose this subset from Arthur J. Riel's Object Oriented Design Heuristics, but I'm sure most books on OO would have similar rules of thumb):
A class should capture one and only one key abstraction. Minimize the number of classes with which another class collaborates. Minimize the amount of collaboration between a class and its collaborator. Minimize fanout in a class. Most of the methods defined on a class should be using most of the data members most of the time. Classes should not contain more objects than a developer can fit in his or her short-term memory. A class must know what it contains, but it should never know who contains it.
How would you address these criticisms? How should java.awt.Component have been designed? Would redesigning to meet these "good" attributes create too poor performance? Is there a GUI toolkit that meets these attributes? And would an API meeting these attributes still be easy to use?
I was thinking that the Artima community minds would be the best ones to ask. What do you think? (Extra points for UML diagrams.)
I'm just shooting from the hip here, but I reckon you have already started step 1, which is to identify the different concerns.
After that was refined, I might look at defining an interface for each of these concerns.
After that I might create a private inner class for each concern (implementing the interface).
In the end I might move every method to an inner class and just have a few methods that gave me a "view" of the Component as a Paintable, or as a HeirarchyMember or whatever.
It wouldn't change much under the hood, but the API documentation would sure be simpler.
I also feel that segregating interfaces is a key step to improving a design.
You have split the Component's interface topically. Another interesting aspect to consider would be which methods in those interfaces tend to be used together (maybe some statistics from existing source code that uses Component would help there).
While creating all those helper (inner or package level) classes implementing each subinterface, it would be quite interesting to have a look at dependencies between the interfaces and between the underlying implementations. I am pretty sure you could isolate independent pieces, not just by topical cohesion, but also by looking at the references in code.
Using interfaces instead of concrete classes opens new ways for testing GUI-dependent code using the "mock objects approach". I believe that the heavy dependence on concrete classes in GUI toolkits (AWT/Swing/SWT - no difference) is one major reason why the client code is so difficult to test automatically.
As far as the performance impact is concerned, you cannot tell much about it without designing some sort of benchmarks up-front that would allow to objectively compare the "before" and "after" states.
I would wonder if the "slicing" should be around the "types" of the Component. When looking at all the methods, it is clear that they don't all apply to all Components. I was thinking of the following Components:
JPanel (or any Container), Label, TextField, & Button.
While they all probably need to support repaint or invalidate, and position sizing, they all don't need to "expose" the fact that they have children or that the children need to be layed out. And what does foreground color mean (or Focus) to a Container?
A "simple" first attempt might be to make Component ONLY support painting (with size & positioning) and Mouse support; and then see what is missing.
GUIs are very complex beasts, so almost every GUI lib has a monster class that provides almost all of the functionality. Qt has the monster Widget class, MFC has the CWnd monster class, Swing has the Component class.