BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Design Patterns - Dependency Injection

Patterns.png




Bookmark and Share





bogotobogo.com site search:

Dependency Injection

"Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it possible to change them, whether at run-time or compile-time."
-wiki.




What is dependency injection (DI) ?

It allows us to standardize and centralize the way objects are constructed in our application by supplying (injecting) an external dependency into a software component rather than creating an dependency within.

Here is a brief description from https://docs.angularjs.org/guide/di. Here is some samples of using it in AngularJS, AngularJS - Dependency Injection.

There are three ways a component (object or function) can get a hold of its dependencies:

  1. The component can create the dependency, typically using the new operator.
  2. The component can look up the dependency, by referring to a global variable.
  3. The component can have the dependency passed to it where it is needed.

The first two options of creating or looking up dependencies are not optimal because they hard code the dependency to the component. This makes it difficult, if not impossible, to modify the dependencies. This is especially problematic in tests, where it is often desirable to provide mock dependencies for test isolation.

The third option is the most viable, since it removes the responsibility of locating the dependency from the component. The dependency is simply handed to the component.





What types of dependency injection are there?

Making a class's dependencies explicit and requiring that they be injected into it is a good way of making a class more reusable, testable and decoupled from others. There are several ways that the dependencies can be injected:

  1. Setter Injection
    Adding a setter method that accepts the dependency is one way of injection point into a class.
    Pros:
    1. Setter injection works well with optional dependencies. If we do not need the dependency, then just do not call the setter.
    2. We can call the setter multiple times. This is particularly useful if the method adds the dependency to a collection. We can then have a variable number of dependencies.
    Cons:
    1. The setter can be called more than just at the time of construction so we cannot be sure the dependency is not replaced during the lifetime of the object (except by explicitly writing the setter method to check if has already been called).
    2. We cannot be sure the setter will be called and so we need to add checks that any required dependencies are injected.

  2. Constructor Injection (the most popular way of injection)
    The most common way to inject dependencies is via a class's constructor. To do this, we need to add an argument to the constructor signature to accept the dependency.
    There are several advantages to using constructor injection:
    1. If the dependency is a requirement and the class cannot work without it then injecting it via the constructor ensures it is present when the class is used as the class cannot be constructed without it.
    2. The constructor is only ever called once when the object is created, so we can be sure that the dependency will not change during the object's lifetime.
    These advantages do mean that constructor injection is not suitable for working with optional dependencies. It is also more difficult to use in combination with class hierarchies: if a class uses constructor injection then extending it and overriding the constructor becomes problematic.

  3. Property Injection
    Just setting public fields of the class directly:
    The disadvantages of using property injection are similar to setter injection but with the following additional important problems:
    1. We cannot control when the dependency is set at all, it can be changed at any point in the object's lifetime.
    2. We cannot use type hinting so we cannot be sure what dependency is injected except by writing into the class code to explicitly test the class instance before using it.
    But, it is useful to know that this can be done with the service container, especially if we are working with code that is out of our control, such as in a third party library, which uses public properties for its dependencies.


Here is a video from Youtube:

I'm sorry; your browser doesn't support HTML5 video in ogv or mp4



Tightly coupled classes

In the code below, the application (Drawing class) is drawing a specified shape.

#include <iostream>
#include <string>
using namespace std;

class Shape
{
public:
  virtual void draw() = 0;
};

class Circle : public Shape
{
public:
  void draw() { cout << "circle\n"; }
};

class Triangle : public Shape
{
public:
  void draw() { cout << "triangle\n"; }
};

class Drawing
{
public:
  void drawShape(string s)
  {
    if(s == "triangle")
      pShape = new Triangle;
    else if( s == "circle")
      pShape = new Circle;

    pShape->draw();
  }

private:
    Shape *pShape;
};

If the drawShape() method is given "triangle" as its parameter, it will draw triangle, if "circle" is given, then it will draw circle. However, in software design perspective, the fact that the instantiation is done within the class itself, the Drawing class is tightly coupled with Triangle and Circle classes.




Dependency Issue

What problems does dependency create?

  1. Code is tightly coupled.
  2. Difficult to isolate the code to test.
  3. Maintenance cost is high.
    If I change code A, how do I know what else did I break?

Now, we want to modify the previous sample code so that we can break the coupling between Drawing and Triangle/Circle classes.

How?




Dependency Injected (DI)
#include <iostream>
#include <string>
using namespace std;

class Shape
{
public:
  virtual void draw() = 0;
};

class Circle : public Shape
{
public:
  void draw() { cout << "circle\n"; }
};

class Triangle : public Shape
{
public:
  void draw() { cout << "triangle\n"; }
};

/* 1. This class does not have hard-coded shapes
   such as Triangle and Circle
   2. So, it's decoupled and has no dependency
   3. The specific information is injected by other class
   4. This code can be remained untouched 
      when we switch the shape to draw  
*/

class Drawing
{
public:
  void drawShape(Shape *pShape)
  {
     pShape->draw();
  }

private:
    Shape *pShape;
};

/* 1. This class pulled the hard-coded shape info out of  
      the Drawing class (compare with the previous example)
   2. This class is an interface that can be modified
      depending on what to draw
   3. This class is doing the dependency injection
*/
class IDrawing
{
public:
  IDrawing() { d = new Drawing; }
  void draw(string s)
  {
    if(s == "triangle")
        d->drawShape(new Triangle);
    else if( s == "circle")
        d->drawShape(new Circle);
    else
        cout << " Need shape";
  }

private:
  Drawing *d;
};

As we can see from the code, the Drawing class does not have hard-coded shapes anymore. Now, it's decoupled and has no dependency. The specific shape information is injected by other interface class (IDrawing) and it does not instantiate anything within the class. Therefore, this code can be remained untouched even though we switch the shape to draw.

The interface class IDrawing pulled the hard-coded shape info out of the Drawing class. This class as an interface can be modified depending on what to draw, and it is doing the dependency injection.




Pros and Cons of Dependency Injection
  1. Pros
    1. Loosely coupled code
    2. Increase testibility
    3. Can use IoC container
  2. Cons
    1. Increase code complexity
    2. Hard to understand code, at least initially








Dependency Injection - Javascript sample

A dependency injection is a software design pattern popularized by a software engineer named Martin Fowler. The main principle behind dependency injection is the inversion of control in a software development architecture. To understand this better, let's have a look at the following notifier example:

var Notifier = function() {
   this.userService = new UserService();
};

Notifier.prototype.notify = function() {
   var user = this.userService.getUser();

   if (user.role === 'admin') {
        alert('You are an admin!');
   } else {
        alert('Hello user!');
   }
};

Our Notifier class creates an instance of a userService, and when the notify() method is called, it alerts a different message based on the user role. Now this can work pretty well, but what happens when we want to test our Notifier class?

We will create a Notifier instance in our test, but won't be able to pass a mock userService object to test the different results of the notify method. Dependency injection solves this by moving the responsibility of creating the userService object to the creator of the Notifier instance, whether it is another object or a test. This creator is often referred to as the injector. A revised version of this example will be as follows:

var Notifier = function(userService) {
   this.userService = userService;
};

Notifier.prototype.notify = function() {
   var user = this.userService.getUser();

   if (user.role === 'admin') {
        alert('You are an admin!');
   } else {
        alert('Hello user!');
   }
};

Now, whenever we create an instance of the Notifier class, the injector will be responsible for injecting a userService object into the constructor, making it possible to control the behavior of the Notifier instance outside of its constructor, a design often described as inversion of control.

This section is from - MEAN Web Development by Amos Q. Haviv









Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong





List of Design Patterns



Introduction

Abstract Factory Pattern

Adapter Pattern

Bridge Pattern

Chain of Responsibility

Command Pattern

Composite Pattern

Decorator Pattern

Delegation

Dependency Injection(DI) and Inversion of Control(IoC)

Façade Pattern

Factory Method

Model View Controller (MVC) Pattern

Observer Pattern

Prototype Pattern

Proxy Pattern

Singleton Pattern

Strategy Pattern

Template Method Pattern

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







C++ Tutorials

C++ Home

Algorithms & Data Structures in C++ ...

Application (UI) - using Windows Forms (Visual Studio 2013/2012)

auto_ptr

Binary Tree Example Code

Blackjack with Qt

Boost - shared_ptr, weak_ptr, mpl, lambda, etc.

Boost.Asio (Socket Programming - Asynchronous TCP/IP)...

Classes and Structs

Constructor

C++11(C++0x): rvalue references, move constructor, and lambda, etc.

C++ API Testing

C++ Keywords - const, volatile, etc.

Debugging Crash & Memory Leak

Design Patterns in C++ ...

Dynamic Cast Operator

Eclipse CDT / JNI (Java Native Interface) / MinGW

Embedded Systems Programming I - Introduction

Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu and Fedora

Embedded Systems Programming III - Eclipse CDT Plugin for gcc ARM Toolchain

Exceptions

Friend Functions and Friend Classes

fstream: input & output

Function Overloading

Functors (Function Objects) I - Introduction

Functors (Function Objects) II - Converting function to functor

Functors (Function Objects) - General



Git and GitHub Express...

GTest (Google Unit Test) with Visual Studio 2012

Inheritance & Virtual Inheritance (multiple inheritance)

Libraries - Static, Shared (Dynamic)

Linked List Basics

Linked List Examples

make & CMake

make (gnu)

Memory Allocation

Multi-Threaded Programming - Terminology - Semaphore, Mutex, Priority Inversion etc.

Multi-Threaded Programming II - Native Thread for Win32 (A)

Multi-Threaded Programming II - Native Thread for Win32 (B)

Multi-Threaded Programming II - Native Thread for Win32 (C)

Multi-Threaded Programming II - C++ Thread for Win32

Multi-Threaded Programming III - C/C++ Class Thread for Pthreads

MultiThreading/Parallel Programming - IPC

Multi-Threaded Programming with C++11 Part A (start, join(), detach(), and ownership)

Multi-Threaded Programming with C++11 Part B (Sharing Data - mutex, and race conditions, and deadlock)

Multithread Debugging

Object Returning

Object Slicing and Virtual Table

OpenCV with C++

Operator Overloading I

Operator Overloading II - self assignment

Pass by Value vs. Pass by Reference

Pointers

Pointers II - void pointers & arrays

Pointers III - pointer to function & multi-dimensional arrays

Preprocessor - Macro

Private Inheritance

Python & C++ with SIP

(Pseudo)-random numbers in C++

References for Built-in Types

Socket - Server & Client

Socket - Server & Client 2

Socket - Server & Client 3

Socket - Server & Client with Qt (Asynchronous / Multithreading / ThreadPool etc.)

Stack Unwinding

Standard Template Library (STL) I - Vector & List

Standard Template Library (STL) II - Maps

Standard Template Library (STL) II - unordered_map

Standard Template Library (STL) II - Sets

Standard Template Library (STL) III - Iterators

Standard Template Library (STL) IV - Algorithms

Standard Template Library (STL) V - Function Objects

Static Variables and Static Class Members

String

String II - sstream etc.

Taste of Assembly

Templates

Template Specialization

Template Specialization - Traits

Template Implementation & Compiler (.h or .cpp?)

The this Pointer

Type Cast Operators

Upcasting and Downcasting

Virtual Destructor & boost::shared_ptr

Virtual Functions



Programming Questions and Solutions ↓

Strings and Arrays

Linked List

Recursion

Bit Manipulation

Small Programs (string, memory functions etc.)

Math & Probability

Multithreading

140 Questions by Google



Qt 5 EXPRESS...

Win32 DLL ...

Articles On C++

What's new in C++11...

C++11 Threads EXPRESS...

Go Tutorial

OpenCV...








Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master