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.
|