toggle menu

[AngularJS] 서비스(service)란 무엇인가?

2012. 11. 8. 15:35 AngularJS
처음 앵귤러JS를 다루다보면, jQuery에 익숙해져있는 사용자일수록 갑작스럽게 등장한 module의 개념과 이를 활용하는 방법, 설정하는 방법에 대해 혼란에 빠진다. 어디서부터 시작되는건지, 지시어와는 어떤 관계인지, 모듈과 서비스의 관계는 무엇이고 또 팩토리(factory)는 무언지 쉽사리 이해하기 어려운 상황에 직면한다.
요러한 어려움을 생각하며, 앵귤러JS에서 서비스를 생성하고 사용하는 간단한 예제를 통해 앵귤러JS에서 서비스를 어떻게 사용하는지 살펴보자.



앵귤러 1.0에서 어플리케이션을 선언하는 표준 정의는 아래와 같다.
var app = angular.module('myApp', []);

하나의 앵귤러 어플리케이션은 적어도 하나의 모듈은 포함하게 된다.
(물론 생략이 가능하지만, 굉장히 단순한 수준만 가능하고 앵귤러의 특징이 무시된다)
모듈의 첫번째 파라메터는 어플리케이션의 이름이다. 아무거나 적으면 안되고, HTML 파일에서 ng-app="어플리케이션명"으로 설정한 이름으로 해주어야 앵귤러JS에서 모듈을 찾을 수 있다.
두번째 파라메터는 [] 배열 형태로 되어 있는데 해당 모듈에서 사용할 다른 모듈들을 적는다. resource나 cookie 등 앵귤러JS에서 미리 만들어둔 모듈들을 등록하는 경우가 많다.


모든 앵귤러 어플리케이션은 이렇게 정의된 어플리케이션(혹은 모듈)에 데이터나 함수들을 담고 있는 컨트롤러를 한 개 이상 붙이게 된다. 
컨트롤러는 대략 아래와 같이 등록해준다.
 
//myApp 모듈에 컨트롤러를 추가한다.
app.controller( 'AppCtrl', function AppCtrl($scope)
{
	$scope.name = 'Guest'; //name이라는 ng-model에 Guest 라는 값을 넣는다.
});

위에서 선언된 모듈과 컨트롤러를 사용하는 간단한 어플리케이션은 대략 아래와 같은 형태가 될 것이다.


module.js 파일
//모듈 선언
var app = angular.module('myApp', []);

//myApp 모듈에 컨트롤러를 추가한다.
app.controller( 'AppCtrl', function AppCtrl($scope)
{
	$scope.name = 'Guest'; //name이라는 ng-model에 Guest 라는 값을 넣는다.
});




HTML 파일
<!doctype html>
<html ng-app="myApp">
	<head>
		<script type="text/javascript" src="http://code.angularjs.org/1.1.0/angular.min.js">
		</script>
		<script type="text/javascript" src="module.js"></script>
	</head>
	<body>
		<section ng-controller="AppCtrl">
			<h1>Hello, {{name}}</h1>
			<div>
				<label for="name">My Name is</label>
				<input name="name" ng-model="name" type="text"/>
			</div>
		</section>
	</body>
</html>


이제 하나의 컨트롤러를 가진 어플리케이션이 만들어졌다.
그럼 여기에 컨트롤러 데이터 일부를 조작하는 서비스를 붙여보자. 

보통 서비스는 하나의 객체를 리턴하는 형태가 주를 이루는데
다양한 함수적인 기능을 수행하는 컨트롤러와는 상당한 차이가 있다.

컨트롤러는 $scope 상의 모델을 조작하거나 UI와 밀접하게 여러 기능들을 수행한다.
반면 서비스는,
서비스 자체가 싱글톤이라는 특성을 사용해 컨트롤러간의 통신을 제어하거나,
리소스 접근 권한을 가진 객체를 리턴해서 컨트롤러에서 이 객체로 CRUD를 수행하거나 하는 방식으로 사용되게 된다.


서비스에 대한 이해는 이정도로 해두고, 실제 모듈에 서비스를 등록하는 방법을 살펴보자.



서비스를 추가하는 첫번째 접근법은 .service() 를 사용하는 방법이다.

app.service('nametrickService', function()
{
	this.reverse = function(name)
	{
		return name.split("").reverse().join("");
	};
});


위에서는 nametrickService 라는 이름의 서비스를 등록했는데, 
.service와 동일하게 사용할 수 있는 메서드로 .factory() 라는 메서드가 존재한다.
 
.factory() 는 어떤 객체를 리턴하기 전에 몇 가지 코드를 실행할 수있는 공간을 제공한다.
요런 특성을 활용해서 서비스와 동일하게 사용될 수 있게 된다.

app.factory('nametrickFactory', function()
{
	return {
		reverse : function(name)
		{
			return name.split("").reverse().join("");
		}
	}
});


nametrickFactory 라는 서비스가 등록되었다.
 
지금까지 하나는 service로 하나는 factory로 서비스를 모듈에 등록했지만, 컨트롤러에 주입하기 전에는 실제로 사용할 수 없다.


초반에 선언했던 컨트롤러를 약간 수정해서 컨트롤러에 위에서 만든 서비스를 컨트롤러에 주입해보자.
더불어 테스트를 위해 우리 서비스를 호출하는 두개의 $scope-level 함수를 설정할 것이다.


app.controller( 'AppCtrl', function AppCtrl($scope, nametrickService, nametrickFactory)
{
	$scope.name = 'Guest';
	
	//nametrickService를 사용하는 스코프레벨 함수 선언
	$scope.reverseNameService = function()
	{
		$scope.name = nametrickService.reverse($scope.name);  
	};
	
	//같은 기능을 하는 nametrickFactory를 사용하는 스코프레벨 함수 선언
	$scope.reverseNameFactory = function()
	{
		$scope.name = nametrickFactory.reverse($scope.name);  
	};
});


스코프 레벨 함수를 호출하기 위해 HTML에도 약간의 추가가 필요하다.
아래의 내용을 HTML 파일의 BODY 후반부에 추가해주자.

<br/>
<button ng-click="reverseNameService()">Reverse Name via Service</button> 
<button ng-click="reverseNameFactory()">Reverse Name via Factory</button> 


이제 소스를 실행해보면, 사실 둘다 동일한 기능을 수행하고 있음을 확인할 수 있다.


지금까지 앵귤러JS에 서비스를 추가하는 두가지 주된 방법을 살펴보았다.

정리해보면, 
.service()  메소드가 아주 약간더 단순한 구조지만, 리소스나 라이브러리를 초기화하는 일회성 설정 작업 같은 경우에는 .factory() 메서드를 사용하면, 서비스 객체를 리턴하기에 앞서서 코드를 실행할 수 있도록 해줄 수 있다.


참조
http://jacobmumm.com/2012/08/28/angular-js-services/

AngularJS 관련 포스팅 더보기