AngularJS/AngularJS

▶ [Angualr2 COOKBOOK] @Injectable

비주얼라이즈 2016. 9. 23. 02:24

▶[Angular2 COOKBOOK] @Injectable


이번 글에서는 Angular를 하다보면 쉽게 마주치게되는 @Injectable 이라는 Decorator에 대해서 입문자의 관점에서 정리해보고자한다.




@Injectable 이란?

Angular에는 여러가지 Decorator가 있다.(@Component, @Input ...등등등.) @Injectable도 이 중 하나이다. 그런데 개인적으로는 (왜인지는 모르겠지만) @Injectable 이라는 Decorator가 다른 Decorator보다 더 뭔가 두려운(?)느낌이든다. 발음도 뭔가 "인젝ㅌ..." 


그래서 Angular API 에서 @Injectable를 쳤더니, 이것에 대한 친절한 한국어 Document가 나왔다!!! 라고 말하고 싶지만, Dependency Injection 이라는 길고긴 페이지가 나온다. @Injectable을 Finder로 찾아보니 이 페이지에서 총 17번이나 등장한다. 


요부분만 살짝 핥고(?) 나오고싶었지만, 이건 아마 정독하라는 Anuglar 개발자들의 의도라고 생각하고 차근차근 접근해보려고한다. 이 문서에서는 Dependency Injection 에서도 @Injectable and nested service dependencies 에 대한 내용이다


만약 이 문서에서 잘못 이해하고있거나, 해석하고있다면 댓글과 방명록으로 도움을 주세요 help us.






@Injectable and nested service dependencies


주입된(Injected) service를 소비하는 곳에서는 해당 Service를 만드는 방법을 알 수 없다. 이것을 걱정하지 않아도 된다. 그것은 Service를 만들고 캐시할 수 있는 의존성 주입(Dependency Injection) 작업이다.



중첩된 서비스 의존성 Nested Service Dependency

뭐라고 정의하는 것도 애매하지만, "중첩된 서비스 의존성" 또는 "서비스 의존성이 중첩적으로 되어있다"라고 생각해볼 수 있겠다. 이것은 우리가 만든 서비스에서 의존성이 있는 어떤 Service를  A라고 할때, 이 A라는 service도 의존중인 service가 있을 수 있다. 이러한 의존관계를 여기서는 Nested Service Dependency라고 말하는 것이다.


이렇게 중첩적으로 서비스 간 의존성이 있는 경우, framework의 일은 중첩된 종속성을 올바르게 해결(또는 정리하는 것)하는 것이다. 


이를 위해, 각 단계에서 종속적인 처리가 이루어지는 consumer는, 필요한 부분에 대해서만 간단히 constructor에서 선언(declare)하고, framework는  이것을 이어받아(take over)처리한다.


다음 예시를 통해 이 개념에 대해서 생각해보자.


 app/app.component.ts 


constructor(logger: LoggerService, public userContext: UserContextService){
    userContext.loadUser(this.userId);
    logger.logInfo('AppComponent initialized');
}

위 코드에서는 LoggerServiceUserContextAppComponent에 주입(inject)하고 있다.


UserContext는 각 사용자에대한 정보를 모으기 위해 LoggerService (again) UserService 에 의존한다.


 user-context.service.ts (injection) 


@Injectable()
export class UserContextService { 
    constructor(private userService: UserService, private loggerService: LoggerService){ }
}


Angular가 AppComponent를 생성할 때, 의존성 주입(Dependency Injection) Framework는 LoggerServiceUserContextService의 인스턴스를 생성하기 시작한다.


UserContextService는 LoggerService, 그리고 이 것을 만들기위해 필요한 UserService가 필요하다. 그런데 UserContextService가 이 두 Service가 필요로할 때 이것들은 아직 생성되지않은 상태이다.


UserService는 의존성(dependencies)가 없다. The UserService has no dependencies so the dependency injection framework can just new one into existence.







왜 Dependency Injection을 알아야하지? 

의존성주입(dependency injection)의 아름다움


AppComponent의 author는 이러한 모든 것들에 대한 걱정을 할 필요가 없다는 데에 있다. author는 단순히 생성자(Logger Service 및  UserContextService)에 필요했던 것 들을 선언(declare)하고 프레임워크에서 나머지 작은 일들을 처리하도록 한다.

이러한 결과로, AppComponent는 모든 의존성(dependency)이 자리를 잘 잡은다음, 사용자정보를 (우리가 설정한대로) 화면에 표현한다.


이미지 : 사용자정보 표현화면 예시

(angular.io > cookbook > dependency injection)




@Injectable


Injectable을 어떻게 실제 사용하고있는지 다음 코드에서 살펴보자.


@Injectable() decorator는 UserContextService class위에 위치하고있음을 기억하자.


user-context.service.ts(@Injectable)


@Injectable()
export class UserContextService {
}

위 코드에서 @Injectable() decorator가 있음으로, Angular는 이 두가지 의존성(LoggerService, UserService)의 type을 식별할 수 있게된다.


기술적으로, @Injectable() decorator는 service class 자체적으로 종속성이 있을 때 필요하다. 그런데 LoggerService는 아무런 의존성이 없다. 우리가 @Injectable()을 생략해도 logger가 동작할 것이다.  그리고 생성된 코드도 약간 더 작다.


Technically, the @Injectable()decorator is only required for a service class that hasits own dependencies. The LoggerService doesn't depend on anything. The logger would work if we omitted @Injectable() and the generated code would be slightly smaller.


그러나 service는 우리가 의존성을 주는 순간 break 할 것이며, 우리는 다시 돌아가서 @Injectable()을 추가함으로써 이를 fix 해야한다.  일관성을 위해서, 여기서는 처음부터  @Injectable()을 추가하여 시간이 지난 후 발생할 상황을 피하기로한다.


Angular에서는 모든 Service Class에 @Injectable 을 적용할 것을 권장한다. 그리고 필요한 경우에만 선택적으로 추가하는 방법도 합리적인 방법이라고 말하고 있다.

(@Injectable을 모든 Service class에 필수적으로  적용 해야한다는 것은아니다.)


AppComponent@Injectable 이 필요하지 않았다. 왜냐하면 component class 는  @Component decorator를 가지고있었기 때문이다. Angular가 TypeScript로 작성될 때, single decorator ― any decorator ― 는 의존성 타입을 식별하기에 충분하다.