Skeletal implementation of factories. This base classe provides no
createFoo methods,
(they must be provided by subclasses), but provides two convenience features:
- An initially empty
#hints to be filled by subclasses
constructors. They are the hints to be returned by
#getImplementationHints.
- An automatic
ServiceRegistry#setOrdering applied
on the basis of subclasses-provided
#priority rank.
When more than one factory implementation is
ServiceRegistry#registerServiceProvider for the same category (i.e. they
implement the same
Factory sub-interface), the actual instance to be used is selected
according their
ServiceRegistry#setOrdering and user-supplied
Hints. Hints have precedence. If more than one factory matches the hints
(including the common case where the user doesn't provide any hint at all), then ordering
matter.
The ordering is unspecified for every pairs of factories with the same
#priority.
This implies that the ordering is unspecified between all factories created with the
#AbstractFactory(), since they all have the same
#NORMAL_PRIORITY level.
How hints are set
Hints are used for two purposes. The distinction is important because the set
of hints may not be identical in both cases:
- Hints are used for creating new factories.
- Hints are used in order to check if an existing factory is suitable.
AbstractFactory do not provides any facility for the first case.
Factories implementations shall inspect themselves all relevant hints supplied by the user,
and pass them to any dependencies. Do not use the
#hints field for
that; use the hints provided by the user in the constructor. If all dependencies are created
at construction time (constructor injection), there is no need to keep user's hints
once the construction is finished.
The
#hints field is for the second case only. Implementations shall copy in this
field only the user's hints that are know to be relevant to this factory. If a hint is
relevant but the user didn't specified any value, the hint key should be added to the
#hints map anyway with a
null value. Only direct dependencies shall be put
in the
#hints map. Indirect dependencies (i.e. hints used by other factories used
by this factory) will be inspected automatically by
FactoryRegistry in a recursive way.
Note: The lack of constructor expecting a
Map argument is intentional.
This is in order to discourage blind-copy of all user-supplied hints to the
#hints map.
Example: Lets two factories, A and B. Factory A need an instance of Factory B.
Factory A can be implemented as below:
Code | Observations |
class FactoryA extends AbstractFactory {
FactoryB fb;
FactoryA(Hints userHints) {
fb = FactoryFinder.getFactoryB(userHints);
hints.put(Hints.FACTORY_B, fb);
}
}
|
- The user-supplied map (
userHints) is never modified.
- All hints relevant to other factories are used in the constructor. Hints relevant to
factory B are used when
FactoryFinder.getFactoryB(...) is invoked.
- The
FactoryA constructor stores only the hints relevant to
FactoryA.
Indirect dependencies (e.g. hints relevant to
FactoryB) will be inspected
recursively by
FactoryRegistry.
- In the above example,
#hints will never be used for creating new factories.
|