본문 바로가기

Tech/Angular

[Angular] 의존성 주입을 위한 서비스 작성

반응형

이미지 출처 : Pixabay

서비스는 앵귤러에서 의존성 주입을 위해 사용되는 요소입니다. 컴포넌트에서 비즈니스 로직을 분리할 수 있지요.

서비스를 사용함으로써 컴포넌트에서 new를 통해 객체를 생성하지 않고 Injectable class에서 데이터를 얻어올 수 있습니다.

Reference : https://angular.io/guide/dependency-injection

 

Angular

 

angular.io

의존성 주입(DI, Dependency Injection)이란 각 객체간의 결합을 느슨하게 만들어 프로그램이 의존성 역전(Dependency inversion)과 단일 책임 법칙(Single responsibility principle)을 따르게 설계하는 디자인 패턴을 의미합니다.

각 구성요소(혹은 객체)간의 관계를 해당 객체 내부(혹은 소스코드)상에 정의하지 않고 외부에 정의하는 것 이라고 설명할 수 있습니다.

제어 역전(IoC)가 조금 더 일반적인 개념입니다. DI는 IoC의 부분집합이라 할 수 있겠습니다.

IoC가 제어에 대한 문제라면 DI는 객체간의 관계에 대한 이야기라고 할 수도 있겠지요.

Reference : https://en.wikipedia.org/wiki/Dependency_injection

 

Dependency injection - Wikipedia

In software engineering, dependency injection is a technique whereby one object supplies the dependencies of another object. A "dependency" is an object that can be used, for example as a service. Instead of a client specifying which service it will use, s

en.wikipedia.org

Reference : https://en.wikipedia.org/wiki/Single_responsibility_principle

 

Single responsibility principle - Wikipedia

The single responsibility principle is a computer programming principle that states that every module, class, or function[1] should have responsibility over a single part of the functionality provided by the software, and that responsibility should be enti

en.wikipedia.org

Reference : https://en.wikipedia.org/wiki/Dependency_inversion_principle

 

Dependency inversion principle - Wikipedia

In object-oriented design, the dependency inversion principle is a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, depe

en.wikipedia.org

Reference : https://en.wikipedia.org/wiki/Inversion_of_control

 

Inversion of control - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Software programming technique In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow.

en.wikipedia.org

의존성 주입 디자인 패턴을 적용함으로서 각 객체간 의존도를 낮추어 코드의 재사용성을 높이고 유지보수를 용이하게 합니다.

 

지난번에 작성한 employees 컴포넌트에 서비스를 추가해 보겠습니다.

터미널에서 다음 명령어를 입력합니다.

ng generate service employees

ng generate service employees

생성된 service는 다음과 같이 구성되어 있습니다 : 

//employees.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class EmployeesService {

  constructor() { }
}

이 서비스는 hero 데이터를 미리 정의해준 mock data 뿐만 아니라 웹 서비스, 로컬 스토리지 등 어디서든지 가져올 수 있습니다.

지금 단계에서는 mock data만 가지고 있기 때문에 해당 데이터를 가져와 getEmployees() 함수를 통하여 반환하도록 작성하겠습니다.

//employees.service.ts
import { Injectable } from '@angular/core';

import { Employee } from './employees/employee';
import { EMPLOYEES } from './employees/employeeList';

@Injectable({
  providedIn: 'root'
})
export class EmployeesService {

  constructor() { }

  getEmployees(): Employee[] {
    return EMPLOYEES;
  }
}

앵귤러 CLI 커맨드 ng generate 는 생성된 service를 root 모듈에 주입합니다. 

root 모듈에 주입된 서비스는 어플리케이션 전역에서 싱글톤 객체로 사용됩니다.

 

Departments service도 작성해 줍니다.

ng generate service departments
//departments.service.ts
import { Injectable } from '@angular/core';
import { Department } from './departments/department';
import { DEPARTMENTS } from './departments/departmentList';

@Injectable({
  providedIn: 'root'
})
export class DepartmentsService {

  constructor() { }

  getDepartments(): Department[] {
    return DEPARTMENTS;
  }
}

이제 /employees/employees.component.ts 파일과 /departments/departments.component.ts 파일로 돌아가서 import EMPLOYEES, import DEPARTMENTS를 삭제하고, Employees와 Departments를 다음과 같은 단순 정의로 변경합니다.

//employees.component.ts
import { Component, OnInit } from '@angular/core';
import { Employee } from './employee';
import { Department } from '../departments/department';

@Component({
  selector: 'app-employees',
  templateUrl: './employees.component.html',
  styleUrls: ['./employees.component.css']
})
export class EmployeesComponent implements OnInit {
  employees: Employee[];	//EDITED!
  rankList: string[] = ['Chairman', 'Vice Chairman', 'President', 'Senior Executive Vice President', 'Senior Managing Director',
  'Managing Director', 'Department Manager', 'Deputy General Manager', 'General Manager', 'Manager', 'Assistant Manager',
  'Chief', 'Assistant Manager', 'Staff', 'Intern'];
  departments: Department[];	//EDITED!
  selectedEmployee: Employee;

  constructor() { }

  ngOnInit() {
  }

  onSelect(employee: Employee): void {
    this.selectedEmployee = employee;
  }

  updateEmployee(newDeptID: string, newRank: string): void {
    this.selectedEmployee.departmentID = +newDeptID;
    this.selectedEmployee.rank = newRank;
  }

}

 

//departments.component.ts
import {Component, Input, OnInit} from '@angular/core';
import { Department } from './department';

@Component({
  selector: 'app-departments',
  templateUrl: './departments.component.html',
  styleUrls: ['./departments.component.css']
})
export class DepartmentsComponent implements OnInit {
  departments: Department[];	//EDITED!
  selectedDepartment: Department;

  constructor() { }

  ngOnInit() {
  }

  onSelect(department: Department): void {
    this.selectedDepartment = department;
  }

}

그리고 각 service를 컴포넌트에 inject해 준 다음, 각 서비스의 getDepartments 혹은 getEmployees 함수를 통해 데이터를 받아오는 함수를 작성합니다.

또한 작성된 각 함수를 ngOnInit() 함수에서 call 합니다.

완성된 각 .ts 파일은 다음과 같습니다 : 

//employees.component.ts
import { Component, OnInit } from '@angular/core';
import { Employee } from './employee';
import { Department } from '../departments/department';
import { EmployeesService } from '../employees.service';	//ADDED!
import { DepartmentsService } from '../departments.service';	//ADDED!

@Component({
  selector: 'app-employees',
  templateUrl: './employees.component.html',
  styleUrls: ['./employees.component.css']
})
export class EmployeesComponent implements OnInit {
  employees: Employee[];
  rankList: string[] = ['Chairman', 'Vice Chairman', 'President', 'Senior Executive Vice President', 'Senior Managing Director',
  'Managing Director', 'Department Manager', 'Deputy General Manager', 'General Manager', 'Manager', 'Assistant Manager',
  'Chief', 'Assistant Manager', 'Staff', 'Intern'];
  departments: Department[];
  selectedEmployee: Employee;

  constructor(private employeesService: EmployeesService, private departmentsService: DepartmentsService) { }

  ngOnInit() {
    this.getEmployees();	//ADDED!
    this.getDepartments();	//ADDED!
  }

  getEmployees(): void {	//ADDED!
    this.employees = this.employeesService.getEmployees();
  }

  getDepartments(): void {	//ADDED!
    this.departments = this.departmentsService.getDepartments();
  }

  onSelect(employee: Employee): void {
    this.selectedEmployee = employee;
  }

  updateEmployee(newDeptID: string, newRank: string): void {
    this.selectedEmployee.departmentID = +newDeptID;
    this.selectedEmployee.rank = newRank;
  }

}

 

//departments.component.ts
import {Component, Input, OnInit} from '@angular/core';
import { Department } from './department';
import { DepartmentsService } from '../departments.service';	//ADDED!

@Component({
  selector: 'app-departments',
  templateUrl: './departments.component.html',
  styleUrls: ['./departments.component.css']
})
export class DepartmentsComponent implements OnInit {
  departments: Department[];
  selectedDepartment: Department;

  constructor(private departmentsService: DepartmentsService) { }

  ngOnInit() {
    this.getDepartments();	//ADDED!
  }

  getDepartments(): void {	//ADDED!
    this.departments = this.departmentsService.getDepartments();
  }

  onSelect(department: Department): void {
    this.selectedDepartment = department;
  }

}

프로젝트를 빌드하여 실행시키면 기존과 같이 동작하는 것을 확인할 수 있습니다.

localhost:4200/employees

 

반응형