I have found that, if you drive out the dependencies of an object and express those dependencies in terms of interfaces, your domain tends to be a lot more clearly defined but that you need to rely far more heavily on your IoC container to address these dependencies. Fortunately, it also allows you to find dependency patterns far more easily and consolidate those dependencies into concrete implementations that have a focus in purpose (a.k.a. the single responsibility principle). Driving out these dependencies from the requirements of the class through interfaces leads to many small, client-specific, interfaces so that anyone that comes across the class later on and wants to try and figure out what the intent is of the code is not going to be distracted by a dependency that has been passed in that has many more methods on it than is needed by the client class itself (a.k.a. the interface segregation principle). Making these dependencies required through either constructor dependency (my personal choix de vie) or property dependency injection (not my favourite because it is more open to runtime errors) is called an inversion of control (a.k.a. the dependency inversion principle) leads to strong reliance on an Inversion of Control container. This method of designing classes and driving out features are two of the three principles of SOLID design.
SOLID is not new (thank you Uncle Bob!) and I think that many of the concepts are generally agreed upon by most developers concerned with good design. What I want to do in this article is try and illustrate how this changes the way you develop your code.
In the first scenario, I am responsible for building a class that shows the name of the application in the title bar of the application window. We’re trying to develop a really strong architecture with as few points of failure as possible so that we can make a change in one spot and it corrects the bug in other spots as well.
- Whether I am using MVP, MVC, MVVM, or straight code-behind classes I’ll have a class that is connected to the User Interface screen (webpage, windows form, mobile device screen, whatever).
class MainPageBackingClass {
// Public property the UI uses to provide the Application Name in the title bar
public string TItleBarText { get { } }
}
- There’s a desire to provide localization for our application and that’s going to be provided somewhere else in our application. My class needs to get the string that puts the application name up on the screen.
class MainPageBackingClass {
public MainPageBackingClass(IMainPageBackingClassStringsProvider stringsProvider) { .. }
// Public property the UI uses to provide the Application Name in the title bar
public string TItleBarText { get { return stringsProvider.ApplicationName; } }
}
interface IMainPageBackingClassStringsProvider { string ApplicationName { get; } }
At this point I don’t care, from the design of my class’ perspective, what is implementing IMainPageBackingClassStringsProvider, I just care that I need something to provide that string for me. The subtle point to notice here is that the class is defining what it needs and driving out it’s dependencies. There is an interface (IMainPageBackingClassStringsProvider) that is providing only the single string. That’s okay.
Okay, I’m done and I feel good about myself. My next assignment is to create a class that assembles an email message. It puts the user’s name in the formatted message.
- I need a class that takes a format-able string and puts the user’s name in it.
- It’s going to need something to provide the formatted message to it.
- And now a method that takes in something that provides the user’s name