ProAngularJS Ch18. 모듈 및 서비스 활용

#실행결과 http://study.jeju.onl/ch18/example.html

이 장에서는 복잡한 웹프로그램 작성을 위해 모듈을 분리하는 Factory, Service, Provider에 대한 부분을 설명하고 있다.

서비스는 주로 횡단 관심사를 구현하는데 사용한다. 전형적인 예로는 로깅, 보안, 네트워킹 등이 있다. 간단히 말해 다른 곳에 속하지 않는 기능을 구현해야 할 때 서비스를 구현하면 된다.
서비스는 애플리케이션 전반에서 재사용할 수 있게 기능을 패키징한다. 모듈은 여러 애플리케이션에서 기능을 재사용하기 쉽게끔 기능을 패키징한다.

주요 내용은 다음과 같다.

  • 모듈을 활용한 애플리케이션 구조화
    – 단일 모듈 방식
    – 새 모듈 생성: 두번째 인자로 [ ]를 넣는다
  • 서비스의 생성 및 활용
    – factory 메서드: 기능을 패키징해서 의존성 배열로 전달
    – service 메서드: 생성자를 서비스로 등록. 생성자는 상속/재사용 등 유연하게 이용
    – provider 메서드: ‘서비스명+Provider’ 이름으로 의존성 주입에 사용.
    서비스의 생성 및 설정 과정을 좀 더 제어할 수 있다.
  • 내장 모듈 및 서비스의 활용
    – $anchorScroll, $animate, $compile, $controller, $document, $exceptionHandler, $filter, $http, $injector, $interpolate, $interval, $location, $log, $parse, $provide, $q, $resource, $rootElement, $route, $routeParams, $sanitize, $sce, $swipe, $timeout, $window

예제중에 자바스크립트의 prototype을 활용하는 부분이 나온다.
이에 대한 설명은 다음을 참고 했다.
#출처 http://insanehong.kr/post/javascript-prototype/

prototype 기반 프로그래밍이란?
객체의 원형인 프로토타입을 이용하여 새로운 객체를 만들어내는 프로그래밍 기법이다.
– 자바스크립트는 Class 가 존재하지 않는다. 그래서 자바스크립트에서는 객체의 원형인 프로토타입을 이용한 클로닝(Cloning: 복사)과 객체특성을 확장해 나가는 방식을 통해 새로운 객체를 생성해 낸다.
– 모든 함수 객체의 Constructor는 prototype 이란 프로퍼티를 가지고 있다. 이 prototype 프로퍼티는 객체가 생성될 당시 만들어지는 객체 자신의 원형이될 prototype 객체를 가리킨다. 즉 자신을 만든 원형이 아닌 자신을 통해 만들어질 객체들이 원형으로 사용할 객체를 말한다. prototype object는 default로 empty Object 를 가리킨다.

#참고: prototype 기반의 자바프로그래밍의 예제

//#예제 2.
var A = function () { };
A.x=function() {
    console.log('hello');
};
// A를 만들어내는 생성자의 prototype에 world가 저장된다
A.prototype.x = function () {
     console.log('world');
};
var B = new A();
var C = new A();
B.x();
> world             // hello는 생성된 객체 A의 데이터라서 공유되지 않는다
C.x();
> world

이에 대한 소스 코드이다.

1) /ch18/example.html

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
 <title> Services and Modules - ProAngularJS</title>
 <link href="/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
 <link href="/node_modules/bootstrap/dist/css/bootstrap-theme.css" rel="stylesheet" />

 /node_modules/angular/angular.js
 /node_modules/angular/angular-route.js

 

 // 다른 모듈을 참조해 사용하려는 경우, 의존성 배열에 명시한다
 angular.module("exampleApp", ["customDirectives", "customServices"])
 // Provider는 .config를 통해 기능 등의 설정을 변경할 수 있어 강력하다
 .config( function( logServiceProvider) {
 logServiceProvider.debugEnabled(true).messageCounterEnabled(false);
 })
 .controller("defaultCtrl", function( $scope,
 logService, debugService, errorService ) {
 
 $scope.data = {
 cities: [ "London", "New York", "Paris" ],
 totalClicks: 0
 };

 $scope.$watch('data.totalClicks', function(newVal) {
 //console.log("Total click count: "+newVal);
 logService.log("Total click count: "+newVal);
 //debugService.log("Total click count: "+newVal);
 });

 });

 
 <!-- AngularJS에서는 의존성을 처리하기 전에 모듈을 모두 로드한다
 ==> 때문에 js 파일의 기술 순서는 문제가 안된다 -->
 http://directives.js
 http://services.js
</head>
<body ng-controller="defaultCtrl">

 
{{ city }}
<h5>Total Clicks: {{ data.totalClicks }}</h5> </div> </body> </html>

2) /ch18/directives.html

// module의 이름만 같고, 인자는 없는 상태로 사용
// ==> 인자가 없으면 기존 모듈에 추가하여 사용하게 되고
/*
angular.module("exampleApp")
.directive("triButton", function() {

  return {
    scope: { counter: "=counter" },
    link: function( scope, element, attrs, ctrl) {
      element.on("click", function(event) {
        console.log("Button click: "+event.target.innerText);
        scope.$apply( function() {
          scope.counter++;
        });
      });
    }
  };

});
*/

// 복잡한 애플리케이션에서는 여러 모듈을 정의하는게 좋다
// ==> 두개의 인자를 넘겨주면 새 모듈을 생성하게 된다
// ==> 생성된 새 모듈을 사용하려면 메인 모듈의 의존성 배열에 넣어주어야 한다!
// 모듈 간에 factory를 이용하는 방법은 동일하다 (ex: 로깅 서비스)

angular.module("customDirectives", [ "customServices" ])
.directive("triButton", function( logService, errorService ) {

  return {
    scope: { counter: "=counter" },
    link: function( scope, element, attrs, ctrl) {
      element.on("click", function(event) {
        // console.log("Button click: "+event.target.innerText);
        //logService.log("Button click: "+event.target.innerText);
        errorService.log("Button click: "+event.target.innerText);

        scope.$apply( function() {
          scope.counter++;
        });
      });
    }
  };

});

3) /ch18/services.html

angular.module("customServices", [])
.factory("logService", function() {

 var messageCount = 0;
 return {
 log: function(msg) {
 console.log("(LOG-" + messageCount++ + ") " + msg);
 }
 };

});

/*
// $get이란 함수를 사용하여 메서드를 정의한다: factory와 유사
angular.module("customServices", [])
.provider("logService", function() {

 return {
 $get: function() {
 return {
 messageCount: 0,
 log: function(msg) {
 console.log("(LOG-" + messageCount++ + ") " + msg);
 }
 };
 }
 };

});
*/

///////////////////////////////////

/*
// Factory와 같은 방식을 사용해도 되긴 하지만, 
// 상속, 재사용 등을 이용할 수 없으므로 유연하지 못하다
angular.module("customServices", [])
.service("logService", function() {

 return {
 messageCount: 0,
 log: function(msg) {
 console.log("Debug: "+(this.messageCount++) + " " + msg);
 }
 };

});
*/

// 생성자 함수: base class??
// 멤버: messageCount, log(), msgType
var baseLogger = function() {
 this.messageCount = 0;
 this.log = function(msg) {
 console.log( "["+this.msgType + "-" + (this.messageCount++) + "] " + msg);
 };
};

// 빈 생성자 함수
var debugLogger = function() {};
// new 연산자로 baseLogger를 prototype 으로 객체 복사
debugLogger.prototype = new baseLogger();
debugLogger.prototype.msgType = "Debug";

// 빈 생성자 함수
var errorLogger = function() {};
// new 연산자로 baseLogger를 prototype 으로 객체 복사
errorLogger.prototype = new baseLogger();
errorLogger.prototype.msgType = "Error";
errorLogger.prototype.messageCount = 1;

// service()를 통해 서비스로 등록
//angular.module("customServices", [])
angular.module("customServices")
.service("debugService", debugLogger)
.service("errorService", errorLogger);

///////////////////////////////////

// logService라는 factory와 같은 서비스 명을 사용했지만,
// 나중에 정의된 provider의 logService로 덮어 씌워진다.
angular.module("customServices")
.provider("logService", function() {

 var counter = true;
 var debug = true;
 return {

 messageCounterEnabled: function( setting) {
 if( angular.isDefined(setting)) {
 counter = setting;
 return this;
 } else {
 return counter;
 }
 },
 debugEnabled: function( setting) {
 if( angular.isDefined( setting)) {
 debug = setting;
 return this;
 } else {
 return debug;
 }
 },

 $get: function() {
 return {
 messageCount: 0,
 log: function(msg) {
 if( debug) {
 console.log("[LOG-" + this.messageCount++ + "] " + msg);
 }
 }
 };
 }

 };
});

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: