Dependency Injection (DI) และ @Injectable

Dependency Injection (DI) คือ Pattern การส่ง Dependency จากภายนอกเข้าไปให้ Class แทนการสร้างเองภายใน Class ทำให้โค้ดแยกหน้าที่ชัดเจน เปลี่ยน implementation ได้ง่าย และทดสอบด้วย Mock ได้สะดวก

Timeline/ประวัติศาสตร์

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
  subgraph Era1["ยุคสร้างเอง / Manual Creation"]
    A["new Service()
ผูกแน่นกับ Class"] end subgraph Era2["ยุค DI Pattern / Dependency Injection"] B["Constructor Injection
ส่ง Dependency จากภายนอก"] C["Mock Friendly
ทดสอบง่ายขึ้น"] end subgraph Era3["ยุค Angular Injector / Angular DI"] D["@Injectable
ลงทะเบียน Service"] E["Injector Hierarchy
Root Module Component"] end A --> B --> C --> D --> E

แนวคิดสำคัญ

ตารางเปรียบเทียบ Provider Scope

วิธีลงทะเบียน Scope Instance เหมาะกับ
providedIn: 'root' ทั้งแอป โดยมาก 1 Instance Service ทั่วไป, API, Shared State
providers ใน NgModule ระดับ Module ตาม Module Feature Module เฉพาะ
providers ใน Component Component Tree Instance ใหม่ State เฉพาะหน้าจอ

Mermaid Diagram: Injector Hierarchy

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart TD
  A["Root Injector
ตัวฉีดระดับแอป"] --> B["Module Injector
ตัวฉีดระดับโมดูล"] B --> C["Component Injector
ตัวฉีดระดับคอมโพเนนต์"] C --> D["Component Class
รับ Service ผ่าน constructor"] D --> E["Service Dependency
ตรรกะหรือ API"]

สมการคณิตศาสตร์: ความซับซ้อนของ Dependency

C = d × m

Code Example

// logger.service.ts
// Service นี้ใช้บันทึกข้อความ และลงทะเบียนใน root injector
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LoggerService {
  log(message: string): void {
    console.log(`[LOG] ${message}`);
  }
}
// course.component.ts
// Component รับ LoggerService ผ่าน constructor แทนการ new เอง
import { Component } from '@angular/core';
import { LoggerService } from './logger.service';

@Component({
  selector: 'app-course',
  template: `<button (click)="save()">Save</button>`
})
export class CourseComponent {
  constructor(private logger: LoggerService) {}

  save(): void {
    this.logger.log('Course saved');
  }
}

// ตัวอย่างการใช้งาน:
// <app-course></app-course>

กิจกรรมท้ายบท

กลับสัปดาห์ที่ 8