Jon wrote: "We simply use different naming <snip> But in fact we have a very similar solution!".
I (still) don't think so. Implementations of ComponentAdapterFactory are tied to (specific, hard-coded) implementations of ComponentAdapter. Also, current implementations of Container are tied to specific implementations of a single ComponentAdapterFactory. Renaming them to "ComponentFactorySelectionPolicy" or anything else does not change that fact. Here's the terminology mapping as it applies to the code links I sent:
Pico Me
------------------------------------------
Component Service
Component instance Component
Container Container
ComponentAdapter ComponentAdapter
ComponentAdapterFactory <<unspecified>>
<<unspecified>> Selector
<<unspecified>> ComponentFactory
There is overlap between "ComponentAdapterFactory" and "Selector", but the latter has a much smaller responsibility. I'll "speak pico" from now on 
Take a look at this code:
public ComponentAdapter createComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters)
throws PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException
{
return new CachingComponentAdapter(super.createComponentAdapter(componentKey, componentImplementation, parameters));
}
I'm saying that should always be written as
container.registerAdapter(
new CachingComponentAdapter(
new SomeOtherComponentAdapter(
componentKey,
componentImplementation,
parameters
)
)
); // this code works with current MutablePicoContainer
or better yet
container.registerAdapter(
componentKey, // the adapter doesn't need to care about
// being subject to any kind of mapping
new CachingComponentAdapter(
new SomeOtherComponentAdapter(
componentImplementation,
parameters
)
)
);
The difference is relatively small from a user perspective but rather big from an implementation perspective (or from a power user perspective). This is because as a power user I cannot get away with simply writing a custom ComponentAdapter; I need to write a ComponentAdapterFactory as well. Furthermore, it is difficult to mix and match multiple ComponentAdapterFactories (it requires adding scoped/hierarchical containers).
Truly decoupling ComponentAdapterFactory from ComponentAdapter and removing some of its current responsibilities (removing them from PicoContainer and references alltogether, in fact) is the only way I've thought of so far that changes this.
"simply put, there are no factories that creates instances of components in Pico, there are only adapters."
that is a Good Thing. But there's factories that create instances of adapters, and pico assumes that there are. I'm not saying adapters must neccessarily use factories; I'm saying PicoContainer (implementations) shouldn't use them either.
I hope I'm making at least some kind of sense to you. Maybe Thomas explains it better @
http://lists.codehaus.org/pipermail/picocontainer-dev/2003-November/001626.html
every time you have a new kind of component you need a new adapter and a new factory. Furthermore, you *can't freely swap* (all factories have an explicit implementation dependency on an adapter). The responsibility split between adapter and factory is in some way broken. One option is to change the relationship: for example from
factory creates adapter
to
factory uses adapter
The combo I like best atm is
adapter uses factory
where a factory is just that, a factory, and the adapter handles everything but the 'new' (and with non-type-3 IoC, the init and dispose). Furthermore, the container need not care or know about factories...
container uses adapter
...is enough.
In my pet container I went further and introduced many-to-many selection policy, where an adapter is associated with a selector inside the container:
Container-<<uses>>----
0..m--->SelectorSelector-
<<locates>>1------>AdapterAdapter-
<<uses>>----1..n--->FactoryThis is essentially a more generic form of a hashmap. In JDK-1.5 terms, the less generic hashmap variant is:
container<key,adapter>
Adapter has-a Factory
In Ruby terms, the selector list functions as a rich switch/case statement, and the selector is the implementation of the '===' operator.
In pseudocode (fragments):
Container.get(arg):
for each selector
if selector.select(arg)
return adapters.get(selector).get()
return null
SingleUseAdapter.get():
return factory.newInstance()
SingletonAdapter.get():
lazyInit()
return instance
Factory.newInstance():
return new Something
Much cleaner. IoC.