SOlID-DIP

DIP: The Dependency Inversion

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

What are dependences?

Traditional Programming and Dependencies

Class Dependencies: Be Honest!

Demo

public class Order
  {
      public void Checkout(Cart cart, PymentDetails paymentDetails, bool notifyCostomer)
      {
          if (paymentDetails.PymentMEthod == PymentMethod.CreditCard)
          {
              ChargeCard(paymentDetails, cart);
          }
          if (notifyCostomer)
          {
              NotifyCustomer(cart);
          }
      }
      private void NotifyCustomer(Cart cart)
      {
          string customerEmail = cart.CustomerEmail;
          if (!string.IsNullOrEmpty(customerEmail))
          {
              using (var message = new MailMessage("someMail@somwere.com", customerEmail))
              using (var clent = new SmtpClient("localHost"))
              {
                  message.Subject = "some subject on" + DateTime.Now;
                  message.Body = "Body";
                  try
                  {
                      clent.Send(message);
                  }
                  catch (Exception ex)
                  {
 
                      Logger.Error("Some Error");
                      throw;
                  }
              }
          }
      }
      private void ChargeCard(PymentDetails paymentDetails, Cart cart)
      {
          using (var paymenetGateway=new PaymentGateway())
          {
              paymenetGateway.Credentials = "some credentials";
              paymenetGateway.AmountToCharge = cart.TotalAmount;
              paymenetGateway.Charge();
          }
      }
  }

The Problem

Dependency Injection

Constructor Injection (instant on the strategy pattern)

Property Injection

Parameter Injection

Refactoring

Refactoring

public class Order
  {
      private readonly Cart _cart;
      private readonly INotifyCustomer _notifyCustomer;
      public interface INotifyCustomer
      {
          void NotifyCustomer(Cart car);
      }
      public Order(Cart cart, INotifyCustomer notifyCustomer)
      {
          _cart = cart;
          _notifyCustomer = notifyCustomer;
      }
      class NotifyCustomerService : INotifyCustomer
      {
          public void NotifyCustomer(Cart cart)
          {
              string customerEmail = cart.CustomerEmail;
              if (!string.IsNullOrEmpty(customerEmail))
              {
                  using (var message = new MailMessage("someMail@somwere.com", customerEmail))
                  using (var clent = new SmtpClient("localHost"))
                  {
                      message.Subject = "some subject on" + DateTime.Now;
                      message.Body = "Body";
                      try
                      {
                          clent.Send(message);
                      }
                      catch (Exception ex)
                      {

                          Logger.Error("Some Error");
                          throw;
                      }
                  }
              }
          }
      }
      
      public void Checkout(Cart cart, PymentDetails paymentDetails, bool notifyCostomer)
      {
          if (paymentDetails.PymentMEthod == PymentMethod.CreditCard)
          {
              ChargeCard(paymentDetails, cart);
          }
          if (notifyCostomer)
          {
              _notifyCustomer.NotifyCustomer(cart);
          }
      }
      private void NotifyCustomer(Cart cart)
      {
          string customerEmail = cart.CustomerEmail;
          if (!string.IsNullOrEmpty(customerEmail))
          {
              using (var message = new MailMessage("someMail@somwere.com", customerEmail))
              using (var clent = new SmtpClient("localHost"))
              {
                  message.Subject = "some subject on" + DateTime.Now;
                  message.Body = "Body";
                  try
                  {
                      clent.Send(message);
                  }
                  catch (Exception ex)
                  {

                      Logger.Error("Some Error");
                      throw;
                  }
              }
          }
      }
      private void ChargeCard(PymentDetails paymentDetails, Cart cart)
      {
          using (var paymenetGateway = new PaymentGateway())
          {
              paymenetGateway.Credentials = "some credentials";
              paymenetGateway.AmountToCharge = cart.TotalAmount;
              paymenetGateway.Charge();
          }
      }
  }

In the example above we can see how for example the "notifyCustomer" class is now being passed to the contractor, you can pass your notification class(dummy) or use the class that was implemented. You can use framework for DI like Ninject to do so

DIP Smells

Where do we instantiate objects?

IoC Containers

Summary

The Dependency Inversion Principle Part 2

Layered / Tiered application design

Traditional(Naive) layered architecture

Here, according the dependency flow the UI layer is always depended on the Business layer who is depended on the data access layer which in turn is depended on the data base and the service layer

These means that the application is difficult to test or change or work with in isolation from a database or the services

We can not depend on abstraction but an explicit instants

Inverted Architecture

Here, all the top modules like data access and ui are depended on the services and models

The Problem with the Naive Architecture

Dependency injection

Summary