Composition Over Inheritance
One of the constant debates in Android-dom is whether “global data” should be maintained
in a singleton or in a custom Application
object. Apparently, the Application
is kept
around until the process hosting that Application
is killed or recycled, meaning that its
lifetime is equivalent to a static data member, such as a classic singleton. That means
that the primary benefit to a custom Application
is that Application
is a Context
, meaning
you have access to a lot of utility methods (e.g., resource getters) that some arbitrary other
singleton would lack.
If you are creating Android library projects or other forms of reusable code, you may want to
have some global data that, in the absence of other considerations, would be a good use for a
custom Application
object. Hence, you might create a library that mandates that those using
your library must use (or extend) your custom Application
object, adding the android:name
attribute to the <application>
element in the manifest to have Android use that custom
Application
subclass.
However, if every library does this, then developers are screwed.
Java does not support multiple inheritance. If Library A says “you must use my custom Application
class” and Library B says “you must use my custom Application
class”, then a developer cannot
use both Library A and Library B.
This is bad, and is a fine example of where inheritance makes things more brittle than they would otherwise need to be.
A better approach — besides perhaps just using an ordinary singleton — would be to use composition:
- Create a class (e.g.,
com.library.a.ApplicationFacet
) with a constructor that takes anApplication
as a parameter, so instances of that class have access to the application-levelContext
- Define an interface (e.g.,
com.library.a.ApplicationMixin
) with a getter for an instance of your class from step #1 (e.g., agimmeMyFacet()
returning anApplicationFacet
) - Mandate that developers implement your interface on their custom
Application
class
This works even with multiple libraries, since a class can implement multiple interfaces. So long as each library is using its own Java package, there will be no collision on the methods or objects.