Designing for Change
Inversion of Control via Dependency Injection

Nate Kohari
About Me


Software Architect at CTI in Akron, OH
Creator of Ninject, a .NET dependency
injection framework
Disclaimer

 There are no
 silver bullets
 Use critical
 thinking when
 evaluating any
 new idea
Goals
What is inversion of control (IoC)?
How can it make our software more
flexible?
What is dependency injection (DI)?
Ho...
Change Happens

Software seems like it should be easy to
change
As a result, people always find reasons to
change it!
Simpl...
Agile Software

 This has given rise to Agile software
 development methodologies
 Project management strategies aren’t
 e...
Divide and Conquer

When a problem is too complex, break it
into smaller, more easily-solvable
problems
Each problem is a ...
Divide and Conquer (cont.)

 Think of your application like a jigsaw
 puzzle
 How should we carve it up?
 How can we recom...
Cohesion

How similar is the code within a given
class?
Highly-cohesive components = more
flexible software
Single Responsi...
Cohesion (BAD)


class Samurai {
  public void Attack(string target) {
    Console.WriteLine(“Chopped {0} in half!”,target...
Cohesion (better)
class Samurai {
  public Sword Weapon { get; set; }
  public void Attack(string target) {
    Weapon.Hit...
Coupling

How much does a given concrete class
require other concrete classes in order to
operate?
Loosely-coupled compone...
Coupling (BAD)
class Samurai {
  public Sword Weapon { get; set; }
  public void Attack(string target) {
    Weapon.Hit(ta...
Coupling (better)
class Samurai {
  public IWeapon Weapon { get; set; }
  public void Attack(string target) {
    Weapon.H...
Coupling (better, cont.)
class Sword : IWeapon {
  public void Hit(string target) {
    Console.WriteLine(“Chopped {0} in ...
Cohesion = Good
 Coupling = Bad
It’s All About Dependencies

 Each piece of your app has other pieces
 that it needs to operate (e.g. a Samurai
 needs an ...
The Dependency Trap

class Samurai {
  public IWeapon Weapon { get; }
  public Samurai() {
    Weapon = new Sword();
  }
}...
The Dependency Trap (cont.)

class Samurai {
  public IWeapon Weapon { get; }
  public Samurai() {
    Weapon = new Sword(...
The Problem of Control

 By creating the Sword within the Samurai
 type, they’re still tightly coupled!
 Objects should no...
Dependency Injection

One way of achieving inversion of control
Create the dependencies somewhere
outside the object, and ...
Dependency Injection
class Samurai {
  public IWeapon Weapon { get; }
  public Samurai(IWeapon weapon) {
    Weapon = weap...
Dependency Injection (cont.)

class Program {
  public static void Main() {
    Samurai sam = new Samurai(new Sword());
  ...
Problems with DI by Hand

Wiring up objects by hand is cumbersome
What if your dependencies have
dependencies of their own...
DI Frameworks

Also called inversion of control containers
DI frameworks are like super-factories
Rather than wiring up de...
DI Frameworks (cont.)


 Using a DI framework lowers the “cost” of
 resolving dependencies to almost zero
 This means you’...
DI Frameworks (cont.)

 Frameworks galore!
 In Java: Guice, Spring, Pico, Nano
 In .NET: Castle Windsor, StructureMap,
 Sp...
DI with Ninject

class Samurai {
  [Inject] public IWeapon Weapon { get; set; }
  public void Attack(string target) {
    ...
DI with Ninject (cont.)
class Program {
  public static void Main() {
    IKernel kernel = new StandardKernel(...);
    Sa...
The Kernel

The kernel is Ninject’s super-factory
Your application should only have one
kernel (except in very complex cas...
DI with Ninject (cont.)

class Samurai {
  [Inject] public IWeapon Weapon { get; set; }
  public void Attack(string target...
Bindings
Bindings are hints that you give to Ninject
Creates a map between a service type and
an implementation type
Lets ...
Bindings (example)

When IWeapon is requested, create a Sword:
Bind<IWeapon>().To<Sword>();



When Samurai is requested, ...
DSL > XML
Other DI frameworks are geared around
defining bindings in XML
XML is verbose, ugly, and not much better
than pla...
Modules

In Ninject, bindings are collected into
modules
Modules are just class definitions
In other containers, you end up...
Modules (example)
class WarriorModule : StandardModule {
  public override void Load() {
    Bind<IWeapon>().To<Sword>();
...
Behaviors

Ninject can also help re-use instances
Singleton, one-per-thread, one-per-
request (web)
Separates instantiatio...
Singleton (typical)
class Shogun {
  private static Shogun _instance = new Shogun();
  public static Instance {
    get { ...
Singleton (Ninject)
[Singleton]
class Shogun {
  public Shogun() { }
  public void RuleWithIronFist() {
    //...
  }
}


...
Advanced Features

Contextual binding: returns different
implementations depending on situation
Loose-coupled events via e...
Contextual Binding
Bind<IWeapon>().To<Sword>(
   When.Context.Target.Tag == “melee”
);

Bind<IWeapon>().To<Crossbow>(
   W...
Contextual Binding
class Swordsman {
  [Inject, Tag(“melee”)]
  public IWeapon Weapon { get; set; }
}

class Archer {
  [I...
Loose-Coupled Events
class Publisher {
  [Publish(“SomeEvent”)]
  public event EventHandler SomeEvent;
}

class Subscriber...
Method Interception

class ComplexObjectFactory {
  [Cache] public void Create() {
    // Do something difficult to create...
Summary

Make your software more flexible by
maximizing cohesion and minimizing
coupling
Carve your app into a jigsaw puzzl...
For More Information

http://ninject.org/
http://kohari.org/
http://twitter.com/nkohari


Questions?
Designing For Change
Upcoming SlideShare
Loading in …5
×

Designing For Change

5,050 views

Published on

Inversion of Control via Dependency Injection - originally presented at Cleveland Day of .NET, May 17, 2008

Published in: Economy & Finance, Technology

Designing For Change

  1. Designing for Change Inversion of Control via Dependency Injection Nate Kohari
  2. About Me Software Architect at CTI in Akron, OH Creator of Ninject, a .NET dependency injection framework
  3. Disclaimer There are no silver bullets Use critical thinking when evaluating any new idea
  4. Goals What is inversion of control (IoC)? How can it make our software more flexible? What is dependency injection (DI)? How can we use DI to achieve IoC? Why should we use a DI framework?
  5. Change Happens Software seems like it should be easy to change As a result, people always find reasons to change it! Simple changes can be very difficult to implement, and have widespread effects
  6. Agile Software This has given rise to Agile software development methodologies Project management strategies aren’t enough You need to build the flexibility into your software itself
  7. Divide and Conquer When a problem is too complex, break it into smaller, more easily-solvable problems Each problem is a concern Separation of Concerns (SoC)
  8. Divide and Conquer (cont.) Think of your application like a jigsaw puzzle How should we carve it up? How can we recombine the pieces? Two measures to consider: cohesion and coupling
  9. Cohesion How similar is the code within a given class? Highly-cohesive components = more flexible software Single Responsibility Principle (SRP)
  10. Cohesion (BAD) class Samurai { public void Attack(string target) { Console.WriteLine(“Chopped {0} in half!”,target); } }
  11. Cohesion (better) class Samurai { public Sword Weapon { get; set; } public void Attack(string target) { Weapon.Hit(target); } } class Sword { public void Hit(string target) { Console.WriteLine(“Chopped {0} in half!”,target); } }
  12. Coupling How much does a given concrete class require other concrete classes in order to operate? Loosely-coupled components = more flexible software Interface Segregation Principle (ISP)
  13. Coupling (BAD) class Samurai { public Sword Weapon { get; set; } public void Attack(string target) { Weapon.Hit(target); } } class Sword { public void Hit(string target) { Console.WriteLine(“Chopped {0} in half!”,target); } }
  14. Coupling (better) class Samurai { public IWeapon Weapon { get; set; } public void Attack(string target) { Weapon.Hit(target); } } interface IWeapon { void Hit(string target); }
  15. Coupling (better, cont.) class Sword : IWeapon { public void Hit(string target) { Console.WriteLine(“Chopped {0} in half!”,target); } } class Crossbow : IWeapon { public void Hit(string target) { Console.WriteLine(“Pierced {0}’s armor.”,target); } }
  16. Cohesion = Good Coupling = Bad
  17. It’s All About Dependencies Each piece of your app has other pieces that it needs to operate (e.g. a Samurai needs an IWeapon) Once you break your app into pieces, you have to glue the pieces back together These are called dependencies
  18. The Dependency Trap class Samurai { public IWeapon Weapon { get; } public Samurai() { Weapon = new Sword(); } } What’s wrong with this code?
  19. The Dependency Trap (cont.) class Samurai { public IWeapon Weapon { get; } public Samurai() { Weapon = new Sword(); } } Samurai is still strongly coupled to Sword!
  20. The Problem of Control By creating the Sword within the Samurai type, they’re still tightly coupled! Objects should not be responsible for creating their own dependencies This is the idea behind inversion of control
  21. Dependency Injection One way of achieving inversion of control Create the dependencies somewhere outside the object, and inject them into it Really just the Strategy pattern used en masse
  22. Dependency Injection class Samurai { public IWeapon Weapon { get; } public Samurai(IWeapon weapon) { Weapon = weapon; } public void Attack(string target) { Weapon.Hit(target); } }
  23. Dependency Injection (cont.) class Program { public static void Main() { Samurai sam = new Samurai(new Sword()); sam.Attack(“the evildoers”); } } This is dependency injection by hand.
  24. Problems with DI by Hand Wiring up objects by hand is cumbersome What if your dependencies have dependencies of their own, etc? DI frameworks to the rescue!
  25. DI Frameworks Also called inversion of control containers DI frameworks are like super-factories Rather than wiring up dependencies manually, just tell the framework how the parts fit together
  26. DI Frameworks (cont.) Using a DI framework lowers the “cost” of resolving dependencies to almost zero This means you’re more likely to make the appropriate separations
  27. DI Frameworks (cont.) Frameworks galore! In Java: Guice, Spring, Pico, Nano In .NET: Castle Windsor, StructureMap, Spring.NET, ObjectBuilder/Unity And of course my personal favorite...
  28. DI with Ninject class Samurai { [Inject] public IWeapon Weapon { get; set; } public void Attack(string target) { Weapon.Hit(target); } } The [Inject] attribute marks the dependency.
  29. DI with Ninject (cont.) class Program { public static void Main() { IKernel kernel = new StandardKernel(...); Samurai sam = kernel.Get<Samurai>(); sam.Attack(“the evildoers”); } } When the Samurai is returned from the call to Get(), it will already be “armed” with a Sword.
  30. The Kernel The kernel is Ninject’s super-factory Your application should only have one kernel (except in very complex cases) All services should be created via the kernel, either via Get() or an [Inject] decoration
  31. DI with Ninject (cont.) class Samurai { [Inject] public IWeapon Weapon { get; set; } public void Attack(string target) { Weapon.Hit(target); } } But wait, IWeapon is just an interface! How does Ninject know what to inject?
  32. Bindings Bindings are hints that you give to Ninject Creates a map between a service type and an implementation type Lets you build future flexibility into your code, and then adjust without changing the code itself Defined via Ninject’s fluent interface
  33. Bindings (example) When IWeapon is requested, create a Sword: Bind<IWeapon>().To<Sword>(); When Samurai is requested, create a Samurai: Bind<Samurai>().ToSelf();
  34. DSL > XML Other DI frameworks are geared around defining bindings in XML XML is verbose, ugly, and not much better than plain text Defining bindings via code lets you take advantage of IDE features (auto-complete, type-safety)
  35. Modules In Ninject, bindings are collected into modules Modules are just class definitions In other containers, you end up with a monolithic XML file Your app can have any number of modules
  36. Modules (example) class WarriorModule : StandardModule { public override void Load() { Bind<IWeapon>().To<Sword>(); Bind<Samurai>().ToSelf(); } } Modules are just code, so you can build in as much intelligence as you want.
  37. Behaviors Ninject can also help re-use instances Singleton, one-per-thread, one-per- request (web) Separates instantiation behavior from code, making it easier to change
  38. Singleton (typical) class Shogun { private static Shogun _instance = new Shogun(); public static Instance { get { return _instance; } } private Shogun() { } public void RuleWithIronFist() { //... } }
  39. Singleton (Ninject) [Singleton] class Shogun { public Shogun() { } public void RuleWithIronFist() { //... } } The first time a Shogun is requested, it will be activated, then on subsequent requests the same instance will be returned.
  40. Advanced Features Contextual binding: returns different implementations depending on situation Loose-coupled events via event broker Method interception (aspect-oriented programming)
  41. Contextual Binding Bind<IWeapon>().To<Sword>( When.Context.Target.Tag == “melee” ); Bind<IWeapon>().To<Crossbow>( When.Context.Target.Tag == “range” ); These conditional bindings examine the activation context of the current object.
  42. Contextual Binding class Swordsman { [Inject, Tag(“melee”)] public IWeapon Weapon { get; set; } } class Archer { [Inject, Tag(“range”)] public IWeapon Weapon { get; set; } } Contextual binding is useful for matching identical type hierarchies.
  43. Loose-Coupled Events class Publisher { [Publish(“SomeEvent”)] public event EventHandler SomeEvent; } class Subscriber { [Subscribe(“SomeEvent”)] public void OnSomeEvent(object obj, EventArgs e) { ... } } Objects can subscribe to event channels without knowing about actual instances.
  44. Method Interception class ComplexObjectFactory { [Cache] public void Create() { // Do something difficult to create object } } Results in a chain of interceptors being called before the method itself is executed.
  45. Summary Make your software more flexible by maximizing cohesion and minimizing coupling Carve your app into a jigsaw puzzle Use a DI framework like Ninject to glue together the pieces
  46. For More Information http://ninject.org/ http://kohari.org/ http://twitter.com/nkohari Questions?

×