programing

AngularJS: 디자인 패턴의 이해

subpage 2023. 3. 15. 19:37
반응형

AngularJS: 디자인 패턴의 이해

이고르 미나르의 이 글의 맥락에서, 앵글의 선두는JS:

MVC vs MVVM vs MVP.많은 개발자들이 토론하고 논쟁하는 데 몇 시간이고 할애할 수 있는 얼마나 논란이 많은 주제인가.

몇 년 동안 각진JS는 MVC(또는 클라이언트 측 변종 중 하나)에 가까웠지만 시간이 지남에 따라 많은 리팩터링과 API 개선 덕분에 MVVM에 가까워졌습니다. $scope 객체는 컨트롤러라고 하는 함수에 의해 장식되는 ViewModel로 간주될 수 있습니다.

프레임워크를 분류하여 MV* 버킷 중 하나에 넣을 수 있는 몇 가지 장점이 있습니다.프레임워크로 구축되고 있는 어플리케이션을 나타내는 멘탈모델을 쉽게 작성함으로써 개발자가 아피스에 더 익숙해지도록 도울 수 있습니다.또한 개발자가 사용하는 용어를 확립하는 데도 도움이 됩니다.

개발자들이 MV*의 허튼소리에 대해 논쟁하는 데 시간을 허비하는 것보다는 잘 설계되고 관심사를 구분하는 멋진 앱을 만드는 것이 낫다고 생각합니다.그리고 이러한 이유로, 나는 앵글을 선언한다.MVW 프레임워크가 되는 JS - Model-View-Anything.'무엇이든'은 '무엇이든 당신에게 맞는 것'의 약자다.

앵글은 프레젠테이션 로직과 비즈니스 로직 및 프레젠테이션 상태를 적절히 구분할 수 있는 유연성을 제공합니다.최종적으로는 그다지 중요하지 않은 일에 대해 열띤 토론이 아니라 생산성과 애플리케이션 유지보수를 촉진하기 위해 사용하시기 바랍니다.

Angular를 구현하기 위한 권장사항 또는 가이드라인이 있습니까?클라이언트측 어플리케이션의 JS MVW(모델 뷰) 설계 패턴

방대한 양의 귀중한 소스 덕분에 Angular에서 컴포넌트를 구현하기 위한 일반적인 권장 사항이 몇 가지 있습니다.JS 앱:


컨트롤러

  • 컨트롤러는 모델과 뷰의 중간 레이어여야 합니다.최대한 얇게 해주세요.

  • 컨트롤러에서는 비즈니스 로직을 사용하지 않는 것이 좋습니다.모델로 이동해야 합니다.

  • 컨트롤러는 메서드 호출(자녀가 부모와 통신하고 싶을 때 가능) 또는 $emit, $broadcast$on 메서드를 사용하여 다른 컨트롤러와 통신할 수 있습니다.발신 및 브로드캐스트메시지는 최소한으로 억제해야 합니다.

  • 컨트롤러는 프레젠테이션이나 DOM 조작에 신경 쓰지 마십시오.

  • 컨트롤러가 중첩되지 않도록 하십시오.이 경우 부모 컨트롤러는 모델로 해석됩니다.대신 모델을 공유 서비스로 주입하십시오.

  • 컨트롤러의 스코프는 뷰와 뷰가 있는 바인딩 모델에 사용해야 합니다.
    프레젠테이션 모델 설계 패턴에 대해모델을 캡슐화합니다.


범위

범위를 템플릿에서는 읽기 전용으로, 컨트롤러에서는 쓰기 전용으로 처리합니다.스코프의 목적은 모델이 아니라 모델을 참조하는 것입니다.

양방향 바인딩(ng-model)을 수행할 때는 스코프 속성에 직접 바인딩하지 마십시오.


모델

각진 모형JS는 서비스에 의해 정의된 싱글톤입니다

모델은 데이터와 디스플레이를 분리하는 뛰어난 방법을 제공합니다.

모델은 일반적으로 정확히 하나의 종속성(일반적으로 $rootScope의 경우 이벤트 이미터의 일종)을 가지며 테스트 가능한 도메인 로직을 포함하고 있기 때문에 유닛 테스트의 주요 후보입니다.

  • 모델은 특정 유닛의 구현으로 간주되어야 한다.그것은 단일 책임 원칙에 입각하고 있다Unit은 실제 세계에서 단일 엔티티를 나타낼 수 있는 관련 로직의 범위를 담당하는 인스턴스이며, 데이터와 상태의 관점에서 프로그래밍 세계에서 이를 기술합니다.

  • 모델은 응용 프로그램의 데이터를 캡슐화하고 해당 데이터에 액세스하여 조작할 수 있는 API를 제공해야 합니다.

  • 모델은 휴대성이 뛰어나야 비슷한 어플리케이션으로 쉽게 이동할 수 있습니다.

  • 모델에서 단위 로직을 분리함으로써 위치 확인, 업데이트 및 유지보수가 더 쉬워졌습니다.

  • 모델은 전체 응용 프로그램에 공통적인 보다 일반적인 글로벌 모델의 방법을 사용할 수 있습니다.

  • 성분 결합을 줄이고 단위 검정성과 사용성을 높이는 데 실제로 종속성이 없는 경우에는 종속성 주입을 사용하여 모형에 다른 모형을 합성하지 않도록 하십시오.

  • 모델에서는 이벤트청취자를 사용하지 않도록 합니다.테스트하기가 더 어려워지고 일반적으로 단일 책임 원칙의 관점에서 모델을 죽입니다.

모델 구현

모델은 데이터 및 상태 측면에서 일부 논리를 캡슐화해야 하므로 구성원에 대한 접근을 구조적으로 제한해야 하므로 느슨한 결합을 보장할 수 있습니다.

Angular로 하는 방법JS 어플리케이션은 공장 서비스 유형을 사용하여 정의합니다.이를 통해 개인 자산 및 메서드를 매우 쉽게 정의할 수 있으며, 공개적으로 액세스할 수 있는 자산도 한 곳에 반환할 수 있으므로 개발자가 실제로 읽을 수 있습니다.

:

angular.module('search')
.factory( 'searchModel', ['searchResource', function (searchResource) {

  var itemsPerPage = 10,
  currentPage = 1,
  totalPages = 0,
  allLoaded = false,
  searchQuery;

  function init(params) {
    itemsPerPage = params.itemsPerPage || itemsPerPage;
    searchQuery = params.substring || searchQuery;
  }

  function findItems(page, queryParams) {
    searchQuery = queryParams.substring || searchQuery;

    return searchResource.fetch(searchQuery, page, itemsPerPage).then( function (results) {
      totalPages = results.totalPages;
      currentPage = results.currentPage;
      allLoaded = totalPages <= currentPage;

      return results.list
    });
  }

  function findNext() {
    return findItems(currentPage + 1);
  }

  function isAllLoaded() {
    return allLoaded;
  }

  // return public model API  
  return {
    /**
     * @param {Object} params
     */
    init: init,

    /**
     * @param {Number} page
     * @param {Object} queryParams
     * @return {Object} promise
     */
    find: findItems,

    /**
     * @return {Boolean}
     */
    allLoaded: isAllLoaded,

    /**
     * @return {Object} promise
     */
    findNext: findNext
  };
});

새 인스턴스 생성

의존성 주입이 분해되기 시작하고 라이브러리가 특히 서드파티의 경우 어색하게 동작하기 때문에 새로운 기능을 반환하는 팩토리는 피하도록 하십시오.

동일한 작업을 수행하는 더 좋은 방법은 팩토리를 API로 사용하여 getter 및 setter 메서드가 연결된 오브젝트 컬렉션을 반환하는 것입니다.

angular.module('car')
 .factory( 'carModel', ['carResource', function (carResource) {

  function Car(data) {
    angular.extend(this, data);
  }

  Car.prototype = {
    save: function () {
      // TODO: strip irrelevant fields
      var carData = //...
      return carResource.save(carData);
    }
  };

  function getCarById ( id ) {
    return carResource.getById(id).then(function (data) {
      return new Car(data);
    });
  }

  // the public API
  return {
    // ...
    findById: getCarById
    // ...
  };
});

글로벌 모델

일반적으로 이러한 상황을 피하고 모델을 적절하게 설계하여 컨트롤러에 주입하여 뷰에서 사용할 수 있도록 합니다.

특히 일부 방법에서는 애플리케이션 내에서 글로벌접근성이 필요합니다.이를 가능하게 하려면 $rootScope에서 '공통' 속성을 정의하고 응용 프로그램 부트스트랩 중에 commonModel에 바인드하면 됩니다.

angular.module('app', ['app.common'])
.config(...)
.run(['$rootScope', 'commonModel', function ($rootScope, commonModel) {
  $rootScope.common = 'commonModel';
}]);

모든 글로벌 메서드는 '공통' 속성 내에 존재합니다.이것은 일종의 네임스페이스입니다.

단, $rootScope에서 직접 메서드를 정의하지 마십시오.이로 인해 뷰 범위 내에서 ngModel 디렉티브와 함께 사용하면 예기치 않은 동작이 발생할 수 있으며 일반적으로 스코프가 흐트러져 스코프 메서드가 문제를 덮어쓰게 됩니다.


자원

리소스를 통해 여러 데이터 원본과 상호 작용할 수 있습니다.

단일 책임 원칙을 사용하여 구현해야 합니다.

특히 HTTP/JSON 엔드포인트에 재사용 가능한 프록시입니다.

리소스는 모델에 주입되어 데이터를 전송/검색할 수 있습니다.

자원 구현

RESTful 서버 측 데이터 원본과 상호 작용할 수 있는 리소스 개체를 생성하는 공장입니다.

반환된 리소스 개체에는 낮은 수준의 $http 서비스와 상호 작용할 필요 없이 높은 수준의 동작을 제공하는 작업 메서드가 있습니다.


서비스

모델과 리소스는 모두 서비스입니다.

서비스는 연결되지 않은 느슨하게 결합된 기능 단위로, 자체 완결됩니다.

서비스는 Angular가 서버 측에서 클라이언트 측 웹 앱에 제공하는 기능으로, 오랫동안 서비스가 일반적으로 사용되어 왔습니다.

각도 애플리케이션의 서비스는 종속성 주입을 사용하여 함께 연결된 대체 가능한 개체입니다.

Angular에는 다양한 유형의 서비스가 있습니다.각각 고유한 사용 사례가 있습니다.자세한 내용은 서비스 유형 이해를 참조하십시오.

어플리케이션에서 서비스 아키텍처의 주요 원칙을 고려해 보십시오.

일반적으로 웹 서비스 용어집에 따르면:

서비스는 제공자 엔티티 및 요청자 엔티티의 관점에서 일관된 기능을 형성하는 태스크를 수행하는 능력을 나타내는 추상적인 자원입니다.서비스를 사용하려면 구체적인 프로바이더 에이전트에 의해 실현되어야 합니다.


클라이언트 측 구조

일반적으로 응용 프로그램의 클라이언트 측은 모듈로 분할됩니다.각 모듈은 하나의 유닛으로 테스트 가능해야 합니다.

모듈을 정의하는 방법은 유형이 아니라 특징/기능 또는 보기에 따라 달라집니다.자세한 내용은 미스코의 프레젠테이션을 참조하십시오.

모듈 컴포넌트는 컨트롤러, 모델, 뷰, 필터, 디렉티브 등의 유형별로 분류할 수 있습니다.

그러나 모듈 자체는 재사용 가능, 이전테스트 가능한 상태로 유지됩니다.

또한 개발자들은 코드의 일부와 모든 종속성을 찾는 것이 훨씬 더 쉽습니다.

각도의 코드 구성을 참조하십시오.자세한 내용은 JSJavaScript Applications를 참조하십시오.

폴더 구성의 예:

|-- src/
|   |-- app/
|   |   |-- app.js
|   |   |-- home/
|   |   |   |-- home.js
|   |   |   |-- homeCtrl.js
|   |   |   |-- home.spec.js
|   |   |   |-- home.tpl.html
|   |   |   |-- home.less
|   |   |-- user/
|   |   |   |-- user.js
|   |   |   |-- userCtrl.js
|   |   |   |-- userModel.js
|   |   |   |-- userResource.js
|   |   |   |-- user.spec.js
|   |   |   |-- user.tpl.html
|   |   |   |-- user.less
|   |   |   |-- create/
|   |   |   |   |-- create.js
|   |   |   |   |-- createCtrl.js
|   |   |   |   |-- create.tpl.html
|   |-- common/
|   |   |-- authentication/
|   |   |   |-- authentication.js
|   |   |   |-- authenticationModel.js
|   |   |   |-- authenticationService.js
|   |-- assets/
|   |   |-- images/
|   |   |   |-- logo.png
|   |   |   |-- user/
|   |   |   |   |-- user-icon.png
|   |   |   |   |-- user-default-avatar.png
|   |-- index.html

각도 애플리케이션 구조의 좋은 예는 angular-app - https://github.com/angular-app/angular-app/tree/master/client/src에 의해 구현됩니다.

이는 최신 애플리케이션 생성기에서도 고려되고 있습니다.https://github.com/yeoman/generator-angular/issues/109

당신이 제공한 인용문에서 보듯이, 이고르의 이번 조치는 훨씬 더 큰 문제의 빙산의 일각에 불과하다고 생각합니다.

MVC와 그 파생 모델(MVP, PM, MVVM)은 단일 에이전트 내에서 모두 훌륭하고 훌륭하지만 서버 클라이언트 아키텍처는 모든 면에서 2개의 에이전트 시스템으로 구성되어 있기 때문에 사람들은 이러한 패턴에 너무 집착하여 당면한 문제가 훨씬 더 복잡하다는 사실을 잊어버리는 경우가 많습니다.이러한 원칙을 고수하려고 하면 실제로는 아키텍처에 결함이 생깁니다.

조금씩 해보자.

가이드라인

표시

Angular 컨텍스트 내에서 뷰는 DOM입니다.가이드라인은 다음과 같습니다.

작업:

  • 범위 변수(읽기 전용).
  • 조치를 취하려면 컨트롤러를 호출합니다.

하지 마세요:

  • 아무 논리나 넣으세요.

매력적이고 짧으며 무해한 외관:

ng-click="collapsed = !collapsed"

이는 Javascript 파일과 HTML 파일을 모두 검사하기 위해 시스템이 어떻게 작동하는지 이해하기 위해 필요한 개발자를 의미합니다.

컨트롤러

작업:

  • 스코프에 데이터를 배치하여 보기를 '모델'에 바인딩합니다.
  • 사용자 액션에 응답합니다.
  • 프레젠테이션 논리에 대처합니다.

하지 마세요:

  • 모든 비즈니스 논리에 대응합니다.

마지막 지침의 이유는 통제관은 주체가 아니라 관점의 자매이며 재사용이 불가능하기 때문이다.

지시문은 재사용이 가능하다고 주장할 수 있지만 지시문 역시 뷰(DOM)와 자매지간이며, 실체에 대응하도록 의도된 것은 아닙니다.

물론, 때로는 뷰가 엔티티를 나타내기도 하지만, 그것은 좀 더 구체적인 경우입니다.

즉, 컨트롤러는 프레젠테이션에 집중해야 합니다.비즈니스 로직을 투입하면 부풀려 관리하기 어려운 컨트롤러가 될 가능성이 높을 뿐만 아니라 우려의 분리 원칙에도 위배됩니다.

따라서 Angular의 컨트롤러는 실제로는 프레젠테이션 모델 또는 MVVM에 가깝습니다.

컨트롤러가 비즈니스 로직을 다루지 않아야 한다면 누가 다루어야 할까요?

모델이란 무엇인가?

클라이언트 모델이 부분적이고 오래된 경우가 많다.

오프라인 웹 응용 프로그램 또는 매우 단순한 응용 프로그램(소수의 엔티티)을 작성하지 않는 한 클라이언트 모델은 다음과 같습니다.

  • 부분적
    • 모든 엔티티를 가지고 있지 않거나(페이지 매김의 경우 등)
    • 또는 모든 데이터가 포함되어 있지 않은 경우(페이지 번호 부여의 경우 등)
  • Stale - 시스템에 여러 사용자가 있는 경우 클라이언트가 보유하고 있는 모델과 서버가 보유하고 있는 모델이 동일한지 확인할 수 없습니다.

실제 모델은 지속되어야 합니다.

전통적인 MCV에서는 모델이 유일하게 유지되고 있습니다.모델에 대해 이야기할 때마다, 이것들은 어느 시점에서는 지속되어야 합니다.클라이언트는 모델을 마음대로 조작할 수 있지만, 서버로의 왕복이 정상적으로 완료될 때까지는 작업이 완료되지 않습니다.

결과들

위의 두 가지 점은 주의할 필요가 있습니다.고객이 가지고 있는 모델은 부분적이고 대부분 단순한 비즈니스 로직만을 포함할 수 있습니다.

에서는 소문자 「」를 현명할 수 .M- 그러니까 진짜 mVC, mVP, mVM이에요.더 큰M버용입입니니다

비즈니스 로직

비즈니스 모델에 대한 가장 중요한 개념 중 하나는 두 가지 유형으로 세분화할 수 있다는 것입니다(세 번째 뷰 비즈니스 모델은 다음 날 이야기이므로 생략합니다).

  • 도메인 로직 - 엔터프라이즈 비즈니스 규칙이라고도 하며 애플리케이션에 의존하지 않는 로직입니다.예를 들어, 다음과 같은 모형이 있습니다.firstName ★★★★★★★★★★★★★★★★★」sirName "", "Getter"와 같은 gettergetFullName()응용 프로그램에 의존하지 않는 것으로 간주할 수 있습니다.
  • 애플리케이션 로직 - 애플리케이션 비즈니스 규칙이라고도 하며 애플리케이션 고유의 규칙입니다.예를 들어 오류 검사 및 처리입니다.

클라이언트 컨텍스트 내의 이 두 가지 모두 '진짜' 비즈니스 로직이 아니라는 것을 강조하는 것이 중요합니다.이 로직은 클라이언트에 중요한 부분만을 다루고 있습니다.애플리케이션 로직(도메인 로직이 아닌)은 서버와의 통신 및 대부분의 사용자 상호작용을 용이하게 하는 역할을 합니다.단, 도메인 로직은 대부분 소규모로 엔티티 고유의 프레젠테이션에 의존합니다.

문제는 여전히 남아 있습니다. 각도가 있는 어플리케이션에서는 어디에 그것들을 던집니까?

3층 또는 4층 아키텍처

이러한 MVW 프레임워크는 모두 3개의 레이어를 사용합니다.

동그라미 세 개.

그러나 클라이언트와 관련하여 다음과 같은 두 가지 근본적인 문제가 있습니다.

  • 이 모델은 부분적이고 오래되어 오래가지 않습니다.
  • 응용 프로그램 로직을 넣을 곳이 없습니다.

이 전략의 대안으로 다음 4계층 전략을 들 수 있습니다.

내부부터 외부까지 4개의 원 - 엔터프라이즈 비즈니스 규칙, 애플리케이션 비즈니스 규칙, 인터페이스 어댑터, 프레임워크 및 드라이버

여기서 가장 중요한 것은 애플리케이션 비즈니스 규칙 계층(사용 사례)입니다. 이 계층은 종종 클라이언트에서 잘못됩니다.

이 계층은 인터랙터(밥 삼촌)에 의해 실현됩니다.이는 Martin Fowler가 운영스크립트 서비스 계층이라고 부르는 것과 거의 동일합니다.

구체적인 예

다음 웹 응용 프로그램을 고려하십시오.

  • 응용 프로그램에는 페이지 번호의 사용자 목록이 표시됩니다.
  • 사용자가 'Add user'를 클릭합니다.
  • 모델이 열리고 사용자 세부 정보가 채워집니다.
  • 사용자가 폼을 채우고 [Submit]를 누릅니다.

이제 몇 가지 일이 발생할 것입니다.

  • 폼은 클라이언트의 유효성을 확인해야 합니다.
  • 요청은 서버로 전송되어야 합니다.
  • 오류가 있을 경우 이를 처리한다.
  • 사용자 목록은 페이지 번호 지정으로 인해 업데이트가 필요할 수도 있고 그렇지 않을 수도 있습니다.

이걸 다 어디에 버려요?

에 "Calling"을 호출하는 되어 있는 $resource이 모든 것은 컨트롤러 내에서 이루어집니다.하지만 더 나은 전략이 있다.

제안 솔루션

다음 그림은 Angular 클라이언트에 다른 애플리케이션로직 레이어를 추가하여 위의 문제를 해결하는 방법을 보여 줍니다.

4박스 - DOM은 컨트롤러(어플리케이션 로직, $resource)를 가리킵니다.

컨트롤러 간의 레이어를 $resource에 추가합니다.이 레이어는 인터랙터라고 불립니다.

  • 서비스입니다.사용자의 경우 다음과 같이 호출할 수 있습니다.UserInteractor.
  • 애플리케이션 로직을 캡슐화하여 사용 사례에 대응하는 메서드를 제공합니다.
  • 서버에 대한 요청을 제어합니다.이 레이어는 컨트롤러가 자유형 파라미터를 사용하여 $resource를 호출하는 대신 서버에 대한 요구가 도메인 로직이 동작할 수 있는 데이터를 반환하도록 합니다.
  • 반환된 데이터 구조를 도메인 로직 프로토타입으로 장식합니다.

따라서 위의 구체적인 예에서 요구하는 사항은 다음과 같습니다.

  • 사용자가 'Add user'를 클릭합니다.
  • 모델을 는 방식으로예: 「」).는 다음과 같은 비즈니스 로직 방식으로 장식됩니다.validate()
  • 합니다.validate()★★★★★★ 。
  • 실패하면 컨트롤러가 오류를 처리합니다.
  • 합니다.createUser()
  • 인터랙터가 $resource를 호출합니다.
  • 응답 시 인터랙터는 모든 오류를 컨트롤러에 위임하고 컨트롤러는 오류를 처리합니다.
  • 응답이 성공하면 인터랙터는 필요에 따라 사용자 목록이 갱신되도록 합니다.

Artem의이지만, Artem의 API 내에서 하는 것이 적합하다는 것을 .return로 이동하는 것을 .오브젝트: object: :앞 、 앞앞 、 : object 、 are object are are are 。

angular.module('myModule', [])
// or .constant instead of .value
.value('myConfig', {
  var1: value1,
  var2: value2
  ...
})
.factory('myFactory', function(myConfig) {
  ...preliminary work with myConfig...
  return {
    // comments
    myAPIproperty1: ...,
    ...
    myAPImethod1: function(arg1, ...) {
    ...
    }
  }
});

경우,return물체가 "너무 혼잡해 보인다"는 것은 본 서비스가 너무 많은 것을 하고 있다는 신호입니다.

AngularJest는 기존 방식으로 MVC를 구현하지 않고 MVVM(Model-ViewModel)에 가까운 것을 구현합니다.ViewModel은 바인더라고도 합니다(각도의 경우 $scope일 수 있습니다).모델--> 우리가 알고 있듯이 각도 모델은 단순하게 오래된 JS 객체 또는 애플리케이션 내의 데이터일 수 있습니다.

뷰--> 각진 뷰JS는 angular에 의해 해석되고 컴파일된HTML입니다.명령 또는 명령 또는 바인딩을 적용함으로써 JS의 요점은 각도로 되어 있으며 입력은 단순한 HTML 문자열(내부)이 아닙니다.HTML)이 아니라 브라우저에 의해 작성된 DOM입니다.

View Model --> View Model은 실제로는 뷰와 각진 모델 사이의 바인더/브릿지입니다.JS의 경우 $scope이며, 컨트롤러에서 사용하는 $scope를 초기화 및 증강합니다.

답을 요약하고 싶다면:비스듬히JS 애플리케이션 $scope는 데이터를 참조하고 컨트롤러는 동작을 제어하며 View는 컨트롤러와 상호 작용하여 레이아웃을 처리합니다.

이 질문에 대해 알기 쉽게 하기 위해 Angular는 정규 프로그래밍에서 이미 접한 다양한 설계 패턴을 사용합니다. 1) 모듈에 대해 컨트롤러 또는 디렉티브, 공장, 서비스 등을 등록할 때 사용합니다.여기에서는, 글로벌한 공간으로부터 데이터를 숨깁니다.모듈 패턴입니다. 2) Angular가 스코프 변수를 비교하기 위해 더티 체크를 사용하는 경우, 여기서는 Observer Pattern을 사용합니다. 3) 컨트롤러의 모든 부모 자녀 스코프는 프로토타입 패턴을 사용합니다. 4) 공장 패턴을 사용하는 서비스를 주입하는 경우.

전체적으로 문제를 해결하기 위해 서로 다른 알려진 설계 패턴을 사용합니다.

언급URL : https://stackoverflow.com/questions/20286917/angularjs-understanding-design-pattern

반응형