Say we have 1001 clients that construct their dependencies directly rather than accept injections. Refactoring the 1001 is not an option according to our boss. We're actually not even allowed access to their source, just the class files.
What we are supposed to do is "modernize" the system that these 1001 clients go through. We can refactor that all we like. The dependencies are part of that system. And some of those dependencies we're supposed to change to have a new implementation.
What we'd like to do is have the ability to configure different implementations of dependencies to satisfy this multitude of clients. Sadly, DI doesn't seem an option since the clients don't accept injections with constructors or setters.
1) Refactor the implementation of the service that the clients use so that it does what the clients need now. Bang we're done. Not flexible. Not complex.
2) Refactor the implementation so that it delegates it's work to yet another dependency that it acquires through a factory. Now we can control which implementation they all use by refactoring the factory.
3) Refactor the implementation so that it delegates it's work to yet another dependency that it acquires through a service locator. Now we can control which implementation they all use by configuring the service locator which might simply be a
hashmap of strings to objects with a little casting going on.
4) Something I haven't even thought of yet.
Minimize the design damage being caused by dragging the old poorly designed client code into the future without adding pointless complexity.
Clients shouldn't know or control the implementation of their dependencies but they insist on building them with
new. We can't control the
new but we do control the class they're building.
What have I failed to consider?
do you really need a possibility to configure between different implementations? For what purpose?
Agility. Lot of unknowns. Management wants potential for change. Only lose dependency on the outside world. Also testing.
do you need need a run time mechanics, or just a compile time mechanics to switch between different implementations? Why?
Compile time mechanics is likely enough. Except for testing.
which granularity do you need to switch between implementations? All at once? Per module (each containing a group of classes)? Per class?
Of the 1001 only one is run through the system at any one time. Changing what all clients use at once is likely fine. Individual control of the dependencies is likely important though.
who needs to control the switch? Only your/your developer team? An administrator? Each client on his own? Or the maintenance developers for the client's code? So how easy/robust/foolproof does the mechanics need to be?
Dev for testing. Administrator as external hardware dependencies change. It needs to be easy to test and configure.
Our goal is to show that the system can be remade quickly and modernized.
actual use case for the implementation switch?
One is, some data will be provided by software until the hardware solution is ready.