Continuing on in the series of me trying to unearth an approach to integrating my domain to make use of external services, I’ve decided to come up with what I so elegantly dub the “Approach 2”. If you’ve forgotten about what we’re trying to do here, then head on over to my first post to refresh the grey matter.
Approach 2: Implement a Service Locator
So given approach 1, we want something that isn’t as fastidious in the requirement of passing in interfaces for the things we want done. It’s at this point I began digging, and came across the Service Locator Pattern.
This approach abandons the previous requirement to pass in the interfaces, but instead, is replaced with the Service Locator pattern which the domain object uses to look-up the appropriate service, and call the appropriate method(s) on it.
- Callers of this method do not need to concern themselves with what interfaces they need to pass in.
- If in the future we decide that this method needs to interact with other services, then we can change the method body to include the look up, and there will be not changes to existing callers because the method signature will stay the same.
- The very strength of this approach is its weakness too. There is no real way of knowing what external services the
order.placeOrder()is going to call on – if any at all! You may not really even care, but the Service Locator pattern approach could get really abused, and you could soon find yourself using the Service Locator to look-up infrastructure services and call them, and in so doing, muddying your bounded context of the domain model. Careful thought needs to be given if this approach is to be adopted…
- Testing proves to be challenging. If you’re using something like Spring, the right thing to do would be to inject the application context into this Service Locator, and let the Service Locator delegate service look-ups to the Spring loaded application context. You’ll also find that you will need a testing equivalent Service Locator which gets used for running your tests because you don’t want to load the entire spring application context just to ensure that a particular service class was looked up and called correctly in your unit test.
- Another fly in the ointment about this approach is the fact that your domain object is now responsible for more than just itself. It has to look up the relevant service(s) it wants to use, which implies that it has outside knowledge of what services exist, which is arguably not something it should really know about. This also begins to break the rules of single responsibility.
Now for some, this approach may look quite clean and simple. I have my own reservations about it, and quite frankly, I’m not satisfied with it. In fact, I’m actually on another mission to find a better approach. I think I have one, but only after much more understanding about what it was I actually needed to achieve, and through a fair amount of trial and error managed to come up with what I think is a reasonable enough approach to tackle external service calls and your domain objects.
Code for this blog post can be found on GitHub here under the module of
Join me in my next post to find out how I begin to re-arrange a few things, to gain some better insight into what it is I’m actually trying to do here.
Until next time!