Dependency Inversion
Telerik Academy Alpha

 

HQC

 Table of contents

Dependency Inversion?

(Inversion of Control)

 What?

  • The term Inversion of Control (IoC) originally meant any sort of programming style
    where an overall framework or runtime controlled the program flow.
  • According to that
    definition, most software developed on the .NET Framework uses IoC.
  • In short, IoC is a much broader term that includes, but isn’t limited to, DI.

 Why?

  • High-level modules should not depend on low-level modules.
     
  • Both should depend on abstractions.
     
  • Abstractions should not depend on details. Details should depend on abstractions.
     
  • You know that it’s not reasonable for a class to have zero dependencies-to have zero coupling.
     
  • The Dependency Inversion Principle is the key to this goal.

 How?

  • Consider a set of classes that need to be instantiated into the correct hierarchy so that you can get the functionality needed.
  • This creates the necessary hierarchy but couples the classes together, directly.
  • You would not be able to use Foo without bringing Bar along with it.

 How?

  • Decouple the implementation of Bar from the use of it in Foo by introducing the interface
  • However, you’ve only decoupled the implementation by separating the interface from it.
  • You may have decoupled the implementation of Bar, but you have left Foo dependent on changes to Bar.

 How?

  • Policy owns the abstraction. Detail depends on policy.
  • If Foo owns the IBar abstraction, you can place these two constructs in a package that is independent of Bar.
  • When you change the implementation of Bar, you are no longer seeing an upward ripple of changes.

Dependency Injection?

 What?

  • Dependency Injection is a set of software design principles and patterns that enable us to develop loosely coupled code.
  • Program to an interface, not an implementation.
  • DI is nothing more than a technique that enables loose coupling. However, there
    are many misconceptions about DI, and sometimes they get in the way of proper
    understanding.
  • Many people refer to DI as INVERSION OF CONTROL (IoC). These two terms are sometimes used interchangeably, but DI is a subset of IoC.

 How to explain it?

  • How to explain Dependency Injection to a 5-year old.
  • When you go and get things out of the refrigerator for yourself,
    you can cause problems. You might leave the door open, you
    might get something Mommy or Daddy doesn’t want you to
    have. You might even be looking for something we don’t even
    have or which has expired.
    What you should be doing is stating a need, “I need something
    to drink with lunch,” and then we will make sure you have
    something when you sit down to eat.

                                                    Wise Guy in stackoverflow.com

 Why?

  • What purpose does DI serve?

  • DI isn’t a goal in itself; rather, it’s a means to an end

    • One aspect of that is to write maintainable code

    • DI is nothing more than a technique that enables loose coupling

      • loose coupling makes code more maintainable

  • Successful software must be able to change

 Myths

  • There are at least four common myths about DI:

    • DI is only relevant for late binding

    • DI is only relevant for unit testing

    • DI is a sort of Abstract Factory on steroids

    • DI requires a DI CONTAINER

 Benefits

Benefit Description When is it valuable?
Late binding Services can be swapped with
other services.
Valuable in standard software, but perhaps less so in enterprise applications where the runtime environment tends to be well-defined
Extensibility Code can be extended and reused
in ways not explicitly planned for.
Always valuable
Parallel
development
Code can be developed in parallel. Valuable in large, complex applications; not so
much in small, simple applications
Maintainability Classes with clearly defined
responsibilities are easier to maintain.
Always valuable
Testability Classes can be unit tested. Only valuable if you unit test (which you really,
really should)

 Real life example

  • Okay, so you can swap out your relational data access component for something
    else.

  • For what?

  • Is there any alternative to relational databases?

  • This has changed significantly in the last years.

  • There are alternatives to relational databases

  • The replacement argument has now become much stronger.

REAL LIFE EXAMPLE

Example

 Example

public static void Main()
{
    IMessageWriter writer = new ConsoleMessageWriter();
    var salutation = new Salutation(writer);
    salutation.Exclaim();
}
  • Hello World application done in DI style

  • Looks complicated 

  • But the benefits it provides are much more valuable

Create concrete writer (Console)

Inject it as dependency

Call the action

 Example

public class Salutation
{
    private readonly IMessageWriter writer;
    public Salutation(IMessageWriter writer)
    {
        if (writer == null)
        {
            throw new ArgumentNullException("writer");
        }

        this.writer = writer;
    }

    public void Exclaim()
    {
        this.writer.Write("Hello DI!");
    }
}

Use dependency

Inject it as dependency

 Example

  • Define the abstraction (interface)

    • It could have other methods as well

Required method

public interface IMessageWriter
{
    void Write(string message);
}

 Example

public class ConsoleMessageWriter : IMessageWriter
{
    public void Write(string message)
    {
        Console.WriteLine(message);
    }
}
  • Create the concrete class

    • Which implements the interface (Console)

    • It could be FileMessageWriter

Concrete implementation

DI(IoC) Containers

 What?

  • A DI CONTAINER is a software library that can automate many of the tasks involved in
    composing objects and managing their lifetimes.
  • Don’t expect a DI CONTAINER to magically make tightly coupled code loosely coupled. A DI CONTAINER can make the use of DI more efficient, but an application must first and foremost be designed with the DI patterns
    and techniques in mind. 

 Why?

  • Imagine that you want to resolve an instance of the class.
    • You could suply it manually
      • But you have no control over lifetime of the object
      • And resolving all the dependencies in the graph
      • Much work to handle it manually
  • You could use container which provides you with all the functionality needed to control the object creation and management

 How?

  • Resolve an instance of the concrete class
var svc = new ShippingService(new ProductLocator(), 
   new PricingService(), new InventoryService(), 
   new TrackingRepository(new ConfigProvider()), 
   new Logger(new EmailLogger(new ConfigProvider())));

Without DI Container

DI Container

var svc = IoC.Resolve<IShippingService>();

 How? (Autofac syntax)

  • How DI Container knows what we want?
    • It is not guessing or coin flipping
    • You tell him what you want!
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ProductLocator>().As<IProductLocator>();
builder.RegisterType<PricingService>().As<IPricingService>();
builder.RegisterType<InventoryService>().As<IInventoryService>();
builder.RegisterType<TrackingRepository>().AsSelf();
builder.RegisterType<ConfigProvider>().AsSelf();
builder.RegisterType<Logger>().AsSelf();
builder.RegisterType<EmailLogger>().As<IMessageLogger>();
var container = builder.Build();

Register all the dependencies

Resolve and get instance

var shippingService = container.Resolve<ShippingService>();

 How? (Ninject syntax)

  • How DI Container knows what we want?
    • It is not guessing or coin flipping
    • You tell him what you want!
IKernel container = new StandardKernel();
container.Bind<IProductLocator>().To<ProductLocator>();
container.Bind<IPricingService>().To<PricingService>();
container.Bind<IInventoryService>().To<InventoryService>();
container.Bind<TrackingRepository>().ToSelf();
container.Bind<ConfigProvider>().ToSelf();
container.Bind<Logger>().ToSelf();
container.Bind<IMessageLogger>().To<EmailLogger>();

Register all the dependencies

Resolve and get instance

var shippingService = kernel.Get<ShippingService>();

 Poor man's DI

  • How would you inject a worker service in a controller class and perhaps a repository in a worker service?
public class HomeController : Controller
{
   private readonly IHomeService _workerService;
   public HomeController() : this(new HomeService())
   {
   }
   public HomeController(IHomeService service)
   {
      _workerService = service;
   }
}

 Poor man's DI

  • The most obvious way is by letting controllers and services create a fresh new instance of the dependent objects.
     
  • This route, however, creates a tight dependency between objects that potentially hinders extensibility and testability.
     
  • For this reason, many suggest inversion of control and IoC containers.

 When?

  • The point of the diagram is that Poor Man's DI can be valuable because it's simple, while a DI Container can be either valuable or pointless depending on how it's used.

Do you really need it all the time?

Containers Catalog

 Containers

 Containers

Questions?

[C# HQC] Dependency Inversion

By telerikacademy

[C# HQC] Dependency Inversion

  • 993