I've been through all of the email on this subject in detail and
carried out a useful exercise. I basically combined all of the
ideas that have been circulating into one big interface. The
result of the combination was a rather unwieldy set of lookup,
query and release operations. I then tried to apply some
rationalisation. The result of a rationalisation is three
distinct interfaces (a) a simple service lookup facility, (b) a
simple selection facility, and (c) a simple pool facility.
interface ServiceManager
{
Object lookup( String role );
boolean hasService( String role );
}
The ServiceSelector interface handles isolation of the case where
supplementary policy is needed. Instead of escalating the number
of lookup arguments on ServiceManager, I'm taking the approach that
a ServiceSelector is returned from a ServiceManager. While I realise
that this is equivalent to lookup( role, policy ), I think this better
clarifies behaviour of ServiceManager by isolation of the abstract
policy argument (policy is forced down to implementation enabling
sophisticated service selection/generation/deployment alternatives).
interface ServiceSelector
{
Object select( Object policy );
boolean isSelectable( Object policy );
}
The ServicePool interface captures the discussion concerning
referenced objects. It is modelled on the assumption that a
ServicePool instance is located via a ServiceManager, therefore,
the pool is dealing with a particular type of pooled object.
Semantics of the interface are that objects that are
"checked-out" must be returned to the pool either individually
or collectively via reference to a token. The criteria argument
on "checkout" is provides as a means by which implementation may
introduce more sophisticated behaviour without being constrained by
the interface.
interface ServicePool
{
Object checkout( Object token );
Object checkout( Object token, Object criteria );
void release( Object object );
void releaseAll( Object token );
}
At a usage level service selection becomes simple, unambiguous and
maintains the loose binding advantage. There is no policy or criteria
so reuse of the ServiceManager is not jeopardised.
MyService service = (MyService) manager.lookup( "MY-ROLE" );
Service selection deals with the case of selection of multiple instances
of a particular service type, qualified by a policy argument. Expressing
policy as an Object means that this interface is abstract so again,
isolation from ServiceManager is a good thing.
ServiceSelector selector = (ServiceSelector )
manager.lookup( "MY-SELECTOR" );
MyService variant = selector.select("MY-HINT");
I'm making the assumption here that pooling implementations will
typically deal with a single type of object. I.e. you will get a
pool for a particular type from a service manager and apply checkout
and release operations against the returned pool.
ServicePool pool = (ServicePool) manager.lookup( "MY-POOL" );
MyService service = pool.checkout( this );
MyService service = pool.checkout( this, myCriteria ); // alternative
pool.release( service );
pool.releaseAll( this ); // alternative
Benefits of the above are a clear separation of concerns between
service location, service selection, and service pooling. The direct
result is that all facilities become unambiguous.
Thoughts ?
Stephen J. McConnell, OSM sarl
digital products for a global economy
http://www.osm.net
mailto:[EMAIL PROTECTED]
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>