I've noticed the following code pattern while browsing through some sources of my project's 3rd party libraries:
public interface MyInterface {
public static class MyClass1 implements MyInterface { ... }
public static class MyClass2 implements MyInterface { ... }
public static class MyClass3 implements MyInterface { ... }
}
Or this one:
public class MyBaseClass {
public static class MyClass1 extends MyBaseClass { ... }
public static class MyClass2 extends MyBaseClass { ... }
public static class MyClass3 extends MyBa开发者_开发技巧seClass { ... }
}
Real life examples:
- SwingX:
org.jdesktop.swingx.decorator.HighlightPredicate
(Source) - Substance:
org.pushingpixels.substance.api.renderers.SubstanceDefaultTableCellRenderer
(Source)
What's the advantage of having a code structure like this?
My first thought was "aggregation", but the same thing could be achieved using plain old packages. So when/why is it better to use public inner classes instead of a package?
I think this is reasoned by aggregation, maybe they're also not worth it to create a top level class. I do this sometimes if something is to small to create a package (to separate them from others) but the corresponding classes should only used within the context of the top level class. In my opinion this is a design decision.
The decorator pattern may be a nice example, they can be applied on the top-level class but are maybe so simple they're not worth it to be also top-level. You can easily show the ownership by using them as inner classes.
That's not that visible at first glance with packages. You directly see the dependent class/interface.
Further it's possible to access the private fields of a class, this could be useful and is more fine-grained than the package private scope.
One use I can think of is to provide ready-made implementations of the interface, publicly available to anyone, but still conceptually tied to the mother interface.
This makes sense only if the interface is simple (thus the inner implementation classes are small), there aren't too many of them, and most of the interface clients actually need them. Otherwise they clutter up the source file, making it harder to understand.
As far as classes and their inner classes are concerned (doesn't apply to interfaces) one difference is that the inner classes might use private members of the outer class, which is not the case if they were 'siblings' (separate top-level classes).
Example:
public class MyBaseClass {
private static String staticField = "outer";
public static class MyClass1 extends MyBaseClass {
public MyClass1() {
MyBaseClass.staticField = "inner1";
}
}
}
This won't work if you moved the MyClass
out of the outer class.
Doing it this way can save you some extra source code files and makes it possible to give the class a nice hierarchical name, i.e. org.foo.bar.XY.Default
instead of org.foo.bar.DefaultXY
An inner interface has to be static in order to be accessed. The interface isn't associated with instances of the class, but with the class itself, so it would be accessed with Foo.Bar
, like so.
I think the reason of public static inner class is an additional tool or utility for "base" class.
When I asked my teacher about this many years ago, he replied that this way you can expose a totally different interface for the same object. Suppose that you have
public class MyBaseClass {
public static class MyClass1 {
public int myClassMethod1() {...}
public int myClassMethod2() {...}
}
...
public void myBaseMethod1() {...}
public void myBaseMethod2() {...}
}
Because instances of MyClass1
have access to the internals of MyBaseClass
, you can expose the same internal behavior as an instance of MyClass1
or as an instance of MyBaseClass
as you needed, even if the methods defined in both classes are totally different.
I never needed to use that, but is really interesting.
精彩评论