Design patterns are one thing that none of us can escape. If you work in the software development industry and as a part of a team, then odds are that you have run into design patterns.
When you boil it down, a design pattern is a approach to coding that solves a specific problem. These patterns are great because they make it possible for other developers to immediately see our code and have some idea of the underlying architecture to it.
Today I'm going to be talking about a newer design pattern, one that I have been using a lot recently and offers several advantages to help decouple your code and build it in a way that separates layers and uses interfaces to remove dependencies...the service locator pattern.
What is a Service Locator Pattern Anyway?
A Service Locator pattern essentially when you boil it down is like a pharmacist. Think about this, when you go to the pharmacist you take a prescription from the doctor of what you need, and you give it to the pharmacist, and based on that script they will give you back the drug on the script, or something that fits the same bill.
A service locator utilizes an interface in the same way. You tell it an interface that your interested in, and it returns a concrete class that implements that interface.
Below is an example of a service locator class, this class is usually implemented as a singleton, and serves as the only way that a concrete class can be called.
Specifically, a service locator operates on the principle of Inversion of Control. Which is a development technique that over the past few years has gained a lot of traction. You could do a whole article series on inversion of control, but can find a great article here.
For our purposes, Inversion of Control refers to the concept that instead of the class making the call deciding what it needs, it instead relies on a different construct to provide the concrete implementations of interfaces.
The key to the ServiceLocator class is that it maintains a dictionary listing of the interfaces and the matching classes that implement that interface. This dictionary is loaded at line 14 above.
Here’s an example:
Now, all of this is well and good but let’s look at some examples. Let’s say we have an application that handles grading for a school. And in that application we have the following code.
The IGrade interface, provides an generic version of what ever grade is made up of. The Assignment class, implements those methods, in addition to providing functionality specific to an exam.
In our service locator, the class would look as follows:
Notice that we added a single line showing the interface, adding to the dictionary an instance of the Interface, with the value being a new instance of the class.
Now, let’s say we have a page that allows us to add assignments, that save method would look like this.
Notice that our method makes no reference to the assignment class, or anything outside of the interface that it needs. This allows us flexibility in that if I want to replace assignment, with Exam, I can do so within the service locator, and have it carry through the entire application.
Why Do We Care?
The benefit of using this approach is that it makes your code more flexible and allows you to swap out old classes for new as requirements change. This allows you to update your application in a way that minimizes the impact to the rest of the application.
Additionally, this can help with testability, because now using a Fakes Assembly, or just a different Service Locator, I can swap out my application classes for testing classes in my test project.
Service Locator is a valuable tool when applied appropriately and should be consider as a way to reduce dependencies and coupling in your applications.