Angular: Dependency Injection vs. Static methods

Photo by Robert Anasch on UnsplashPhoto by Robert Anasch on Unsplash

In everyday life, problems often arise from choice. The more chances we have to run an activity, the harder it will be to choose. This also happens in development, and today more than ever we have many tools that allow us to achieve the same results in different ways.

Today we quickly explain when and why to use dependency injection on Angular over static classes.

Dependency Injection

Dependency injection (DI) is an important application design pattern. Angular has its own DI framework. In particular, is a coding pattern in which a class asks for dependencies from external sources instead of creating them itself.

Remember that when we talk about dependencies, we mean services or objects that a class needs to perform its function.

Suggestion:

The Angular team recommends you separate components and services in multiple files.

That's why it can be confusing and because if you chose to condense all in one file, you have to define the service before the component if you don't want to slip into a runtime null reference error.

Following the command for generating with Angular CLI a new “MagicianService” class in the path “src/app/magic”.

ng generate service magic/magician

Why Dependency injection?

Angular with the dependency injection framework doesn't do anything that isn't already familiar to most developers.

Nevertheless, the main goal is to avoid tightly coupled components by injecting dependencies rather than instantiating them directly in components. So, decoupling services and components, these last ones are more flexible since you can inject different implementations to the same component.

In fact, a very helpful feature of DI is tokens.

Injection tokens are a feature of Angular that provides a mechanism to link a token to a value and having available that value injected into a component.

Pay attention to…

The typical behaviour of Angular developers is to record all providers in AppModule (the root module). This is useful because in this way all components can access the same instance of the service creating to all effects a Singleton.

Services are singletons within the scope of an injector

What does this quote from the documentation mean?

Recording all providers in the root module makes a sync component effect in which if a component changes a property within the service, all the other components can access the same value of the property.

but

What happens when you instantiate the same service twice, in different sub-modules?

In this situation, all components under a specific sub-module will have the same service and all value properties. However, this is completely unlinked to the service injected in the other sub-module so as to lose the sync effect across the application, keeping it only in the submodule branch.

Why static methods Class?

Let's be concrete:

  • Is it just a function?

  • Does it have no dependencies?

  • Do you want it to be pure?

In these simple cases, you should use static Class.

In deep

Static methods of a class, unlike instance methods, are visible on the class itself and they are not an instance of it.

Typically, when we talk about a static method, it takes input from the parameters, performs actions on it, and returns a result independently of your application.

I'm talking about utils functions, a session service that is useful to be accessible to all the application, and all those cases that don't care to know anything about the execution.

Furthermore, static methods don't have any impact on performances, and invoking them will in no way instantiate the class.

Take a look at this example of usage:

import { MagicianService } from '../services/magic/magician.service';

export class PerformanceComponent {

   constructor() {
      // Note that I didn't inject the service or instantiated it like new MagicianService()
      const bunniesNumber = MagicianService.getBunniesNumber(1,5);

      console.log(bunniesNumber); // => 3

   }

Something you should consider

When we assign a method to the class function itself and to its “prototype”, the value of this in the static method is the class constructor itself.

Let's see an example:

export class SessionService {

   static test() {
      alert(this === SessionService);
   }

}

If you call the “test” method, the alert will print “true”.

SessionService.test(); // => true

Conclusions

It's always arduous to choose which way is the best.

We should analyze case by case but as a main rule, it's recommended that if a method can grow in complexity and dependencies can be necessary, it's better you start your code by dependency injection.

Instead, if your function will remain simple, it's not necessary that it knows part of your business logic and belongs to the class and not any particular object, you should use static methods and properties.

Thanks a lot for reading!

Enjoyed this article?

Share it with your network to help others discover it

Continue Learning

Discover more articles on similar topics