Wow, can't believe that Joel would favor this:
var svc = new ShippingService(new ProductLocator(),
new PricingService(), new InventoryService(),
new TrackingRepository(new ConfigProvider()),
new Logger(new EmailLogger(new ConfigProvider())));
over this:
var svc = IoC.Resolve<IShippingService>();
Many folks don't realize that your dependencies chain can become nested, and it quickly becomes unwieldy to wire them up manually. Even with factories, the duplication of your code is just not worth it.
IoC containers can be complex, yes. But for this simple case I've shown it's incredibly easy.
Okay, let's justify this even more. Let's say you have some entities or model objects that you want to bind to a smart UI. This smart UI (we'll call it Shindows Morms) wants you to implement INotifyPropertyChanged so that it can do change tracking & update the UI accordingly.
"OK, that doesn't sound so hard" so you start writing.
You start with this:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CustomerSince { get; set; }
public string Status { get; set; }
}
..and end up with this:
public class UglyCustomer : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
string oldValue = _firstName;
_firstName = value;
if(oldValue != value)
OnPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
string oldValue = _lastName;
_lastName = value;
if(oldValue != value)
OnPropertyChanged("LastName");
}
}
private DateTime _customerSince;
public DateTime CustomerSince
{
get { return _customerSince; }
set
{
DateTime oldValue = _customerSince;
_customerSince = value;
if(oldValue != value)
OnPropertyChanged("CustomerSince");
}
}
private string _status;
public string Status
{
get { return _status; }
set
{
string oldValue = _status;
_status = value;
if(oldValue != value)
OnPropertyChanged("Status");
}
}
protected virtual void OnPropertyChanged(string property)
{
var propertyChanged = PropertyChanged;
if(propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
That's disgusting plumbing code, and I maintain that if you're writing code like that by hand you're stealing from your client. There are better, smarter way of working.
Ever hear that term, work smarter, not harder?
Well imagine some smart guy on your team came up and said: "Here's an easier way"
If you make your properties virtual (calm down, it's not that big of a deal) then we can weave in that property behavior automatically. (This is called AOP, but don't worry about the name, focus on what it's going to do for you)
Depending on which IoC tool you're using, you could do something that looks like this:
var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());
Poof! All of that manual INotifyPropertyChanged BS is now automatically generated for you, on every virtual property setter of the object in question.
Is this magic? YES! If you can trust the fact that this code does its job, then you can safely skip all of that property wrapping mumbo-jumbo. You've got business problems to solve.
Some other interesting uses of an IoC tool to do AOP:
- Declarative & nested database transactions
- Declarative & nested Unit of work
- Logging
- Pre/Post conditions (Design by Contract)