I am glad we are starting to speak common language:

Originally Posted by
constv
Is your "manager" essentially a business service? Does "Currency Manager" implement currency-related use-cases, and there should be different implementations for currency manipulations for different user types. Am I getting it right?
Yes, you are right.

Originally Posted by
constv
There is nothing polymorphic in the first approach you have just described. You would simply be aggregating all you methods from all your managers under the umbrella of a single interface, and then delegating. I don't see how this can simplify anything. Definitely, not a good option.
You are wrong, it would be polymorphic behavior since you would see UserTypeOperationManager interface and its implementations:
UserTypeOperationManagerForEmployees
UserTypeOperationManagerTeamLeader
UserTypeOperationManagerForJanitor
...
These implementations would contain system-wide user specific behavior in contrast with manager scoped as proposed in solution 2.
Take a look at example
Code:
CurrencyManager(){
doSth(){
switch(userType)
manager
doSthForManager();
employee:
doSthForEmployee();
teamleader:
doSthForTeamLeader
}
}
Code:
UserManager(){
doFoo(){
switch(userType)
manager
doFooForManager();
employee:
doFooForEmployee();
teamleader:
doFooForTeamLeader
}
}
so after refactoring my UserTypeOperationManager inerface will have 2 methods:
doSth
doFoo
These methods would be implemented by user type specific implementations.
UserTypeOperationManager implementations will be used (injected) by UserManager and CurrencyManager. That's how i would use polymorphisms to get rid off switch statements.

Originally Posted by
constv
The second option, indeed, implies polymorphism - all types of users are treated exactly the same by each category of managers. So, if my assumption about your "managers" is correct (and I am not so sure) you would have:
CurrencyManager (interface)
Implementations:
CurrencyManagerForEmployees
CurrensyManagerForTeamLeader
CurrencyManagerForJanitor
etc.
The same for other "categories of managers". Everything in your application will only talk to the interface (e.g. CurrencyManager), and the actual implementation will be resolved on the fly for the user at hand. Not sure why you need to attach anything to ThreadLocal (saw that in your original post.) I envision some controller class - that needs to invoke operations on the currency managers - injected with some CurrencyManagerResolver. Each time such an operation is required for the user, the controller does it not directly on the currency manager instance but via the resolver, passing the user object or user type argument.
Code:
@Autowired(Required=true)
CurrencyManagerResolver cmr;
...
...
// time to call a currency operation
Currency salary = cmr.getManager(user.getType()).calculateSalary(user);
The second option is very similar to the first one. But in this case instead of encapsulating user type dependent code into 1 interface you are providing user type specific implementations of each of managers.
The thing about thread local and using custom targetSource is a spring mechanism you could employ to get rid off Resolvers/Mappers you proposed. "userType specific managers"/"usertype specific implementations of UserTypeOperationManager" would be properly dependency injected by Spring. If you are not familiar with this mechanism you could think of it as being similar to what aop scoped proxy provides.