Dependency injection: What I am taught and why I don't understand that

I am currently learning myself Angular 2. I found this video which I found particularly helpful in this: https://www.youtube.com/watch?v=_-CD_5YhJTA

However, with regards to dependency injection, a topic Mosh starts on 36:40, I do not seem to fully understand his arguments.

Namely, he states (at 41:50) that by writing the constructor like this

export class CoursesComponent {
    title = "The title of courses page";
    courses;

    constructor (courseService: CourseService) { 
        this.courses = courseService.getCourses();
    }
}

“we wrote a component that is no longer tightly coupled to the service” (quote).

Now I tried to convince myself that it is, but I cannot see how it is. Indeed, we could create a mock service CourseService for other usages of this class. However, there is explicit reference in the constructor to a method which is defined in the service CourseService. In my mind, this makes it clearly not a reusable (and testable) class in this way.

Wouldn’t it make much more sense to write something like

constructor (courseService) { 
    this.courses = courseService;
}

and then to let us worry about what we pass to the constructor somewhere else. Then, in my mind, we are honestly decoupled from the service.

But am I right? Or am I missing the point here? And also, as I am a novice, but in case that I have a point, perhaps somebody could propose and alternative for writing this class along the lines of my concerns?

Thanks a lot.

Willem

4
Leave a Reply

avatar
4 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest

In addition to @Piccis answer. Hollywood principle (loose coupling) The main thing here is similar to the Hollywood principle. “Don’t call us, we call you” If you would use new Xxx() in your class it would be very tight coupling: export class CoursesComponent { title = "The title of courses page"; courses; constructor () { let courseService = new CourseService(); this.courses = courseService.getCourses(); } } but with the original code from your question any class that extends CourseService can be passed in and it is also possible to define how this injected instance should be initialized (see next code snipped… Read more »

Jason
Guest

I think the secret is that you can inject a different implementation of CourseService from your main.ts (or whatever file defines your initial bootstrap).

This is an example that could work

import {provide}    from 'angular2/core';

import {bootstrap}    from 'angular2/platform/browser';

import {AppComponent} from './app.component';

import {CourseService} from './course.service';
import {MyCourseService} from '../myImplementation/myCourse.service';

bootstrap(AppComponent, 
            [provide(CourseService, {useClass: MyCourseService})]);

I hope this helps

Jason
Guest

Coupling would assume excessive dependency on Service. I guess it is not the case here since Service has clean interface – getCourses(). We could make it even less coupled injecting interface with opaque token like IService{getCourses()} and it would make the code complicated and less convinient to use, but…

JavaScript allows us to mock or provide different implementations at runtime without casting errors(duck typing). Check this article.

Jason
Guest

I’m fairly new to Angular 2 but my understanding is that Angular 2 has hierarchical injectors, I can certainly see the constructor typing being useful in telling Angular to find the nearest ancestor instance of the injectable to use. There could be benfits in using sub-classes of courseService so you
can have different behaviour depending on the component context.

More on hierarchical injectors:
https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html