Java Reference
In-Depth Information
In cases like this it's important to ensure that you keep your class space as wide as pos-
sible. If three implementations of this
API
were present in the runtime, then clients
would only be able to use one implementation at a time, determined by the
API
pack-
age they're wired to, making the other two implementations redundant. Clearly this
isn't ideal.
SUBSTITUTABILITY
Do you remember learning about shadowing (section 5.1.2)? In your current predica-
ment, shadowing becomes useful. If your bundles both import
and
export the
API
packages, then the runtime will play a clever trick. If the
API
packages
aren't
already
available when your bundle is resolved, then the
import
statement is ignored and the
API
packages are
exported
from your bundle. If the
API
packages
are
available, then the
export
statement is ignored and the
API
packages are
imported
into your bundle. This
arrangement means that there will only be one instance of the
API
package available
in the framework, shared between all of the implementations. This means that clients
can use any of the implementations.
If dependencies are only on interfaces, to the point where implementations can be
swapped in and out at will, how does anything get hold of concrete instances of these
interfaces? If you're thinking in terms of conventional Java, you probably already have
an answer ready—the factory pattern.
5.2.3
Avoid static factory classes
The factory pattern is extremely prevalent in Java; static factories are used to provide
indirection between interfaces and implementations. Although this pattern is techni-
cally possible in
OSG
i, it's unable to cope with
OSG
i's dynamism. If you do create an
object using a static factory, then you won't get any notification when the bundle that
provided it is stopped or even uninstalled. What's worse is that because the static fac-
tory is unlikely to be
OSG
i aware, it won't be tracking its dependencies either. This
means that watching the lifecycle of the bundle that hosts the static factory isn't always
good enough to tell you that your object has become invalid.
The ability to register for Service Registry event notifications as well as the Service
Registry's get/release semantics provide exactly the lifecycle structure that's missing
from the static factory model. If you had used static factories to build your superstore,
then you wouldn't be able to dynamically add and remove special offers. What's worse,
you wouldn't have been able to prevent people from seeing the special offer even if
you removed the department, causing failures elsewhere. And you could never have
separated out your interface and implementation bundles if you had to provide a
static factory that was closely coupled to implementation internals.
As you try to break the static factory habit and replace it with services, you may find
you have to change how you're thinking in other areas. For example, the apparently
inoffensive listener pattern often relies heavily on the factory pattern. Just as they
allow you to avoid static factories,
OSG
i services also allow you to get more from your
listener while writing less code.