모델 데이터 및 동작은 어디에 배치해야 합니까?[tl;dr; 서비스 사용]
Angular와 함께 일하고 있습니다.JS가 내 최근 프로젝트의 JS입니다.설명서 및 튜토리얼에서는 모든 모델 데이터가 컨트롤러 범위에 포함됩니다.컨트롤러가 사용할 수 있게 되려면 해당 뷰 내에 있어야 한다는 것을 이해합니다.
그러나 나는 그 모델이 실제로 그곳에서 구현되어야 한다고 생각하지 않는다.예를 들어 복잡하고 개인 속성이 있을 수 있습니다.또한 다른 컨텍스트/앱에서 재사용할 수도 있습니다.모든 것을 컨트롤러에 넣으면 MVC 패턴이 완전히 깨집니다.
모든 모델의 동작에 대해서도 마찬가지입니다.DCI 아키텍처를 사용하여 데이터 모델과 동작을 분리하려면 동작을 유지하기 위해 추가 객체를 도입해야 합니다.이것은 역할과 컨텍스트를 도입함으로써 이루어집니다.
DCI == 데이터 협업 상호 작용
물론 모델 데이터와 동작은 평이한 Javascript 객체 또는 "클래스" 패턴으로 구현할 수 있습니다.하지만 Angular는 뭘까?JS의 방법?서비스 사용?
결론은 다음과 같습니다.
Angular에 이어 컨트롤러에서 분리된 모델을 구현하려면 어떻게 해야 합니까?JS의 베스트 프랙티스?
여러 컨트롤러에서 사용할 수 있는 것을 원하는 경우 서비스를 사용해야 합니다.다음으로 간단한 예를 제시하겠습니다.
myApp.factory('ListService', function() {
var ListService = {};
var list = [];
ListService.getItem = function(index) { return list[index]; }
ListService.addItem = function(item) { list.push(item); }
ListService.removeItem = function(item) { list.splice(list.indexOf(item), 1) }
ListService.size = function() { return list.length; }
return ListService;
});
function Ctrl1($scope, ListService) {
//Can add/remove/get items from shared list
}
function Ctrl2($scope, ListService) {
//Can add/remove/get items from shared list
}
저는 현재 이 패턴을 시도하고 있습니다.DCI는 아니지만 고전적인 서비스/모델 디커플링(웹 서비스(일명 모델 CRUD) 및 객체 속성 및 메서드를 정의하는 모델 포함)을 제공하고 있습니다.
모델 오브젝트에 독자적인 속성으로 동작하는 메서드가 필요할 때만 이 패턴을 사용합니다(개선된 getter/setter 등).모든 서비스에 대해 체계적으로 이 작업을 수행하는 것을 지지하는 것은 아닙니다.
편집: 예전에는 "Angular model is plain old javascript object"라는 주문에 반하는 패턴이라고 생각했는데, 지금은 이 패턴이 완벽하게 괜찮은 것 같습니다.
편집 (2): 보다 명확하게 하기 위해 모델 클래스는 단순한 getter/setters(보기 템플릿에서 사용하는 예)에만 사용합니다.대규모 비즈니스 로직의 경우 모델에 대해 '알고' 있지만 그것과는 분리되어 비즈니스 로직만을 포함하는 별도의 서비스를 사용할 것을 권장합니다.필요에 따라 "비즈니스 전문가" 서비스 계층이라고 부를 수 있습니다.
service/ElementServices.js(선언문에 요소가 삽입되는 방법에 주의)
MyApp.service('ElementServices', function($http, $q, Element)
{
this.getById = function(id)
{
return $http.get('/element/' + id).then(
function(response)
{
//this is where the Element model is used
return new Element(response.data);
},
function(response)
{
return $q.reject(response.data.error);
}
);
};
... other CRUD methods
}
model/Element.js(개체 작성용으로 제작된 angularjs Factory 사용)
MyApp.factory('Element', function()
{
var Element = function(data) {
//set defaults properties and functions
angular.extend(this, {
id:null,
collection1:[],
collection2:[],
status:'NEW',
//... other properties
//dummy isNew function that would work on two properties to harden code
isNew:function(){
return (this.status=='NEW' || this.id == null);
}
});
angular.extend(this, data);
};
return Element;
});
Angularjs 문서에는 다음과 같이 명시되어 있습니다.
다른 많은 프레임워크와 달리 Angular는 모델에 어떠한 제한이나 요구사항도 두지 않습니다.모델에 액세스하거나 변경하기 위한 상속원 클래스나 특별한 접근자 메서드는 없습니다.모델에는 프리미티브, 오브젝트 해시 또는 풀오브젝트 타입이 있습니다.즉, 이 모델은 플레인 JavaScript 객체입니다.
그러니까 모델을 어떻게 선언하는지는 당신에게 달렸다는 뜻이죠.단순한 Javascript 객체입니다.
Angular Services는 어플리케이션 전체에서 글로벌 상태를 유지하기 위해 사용할 수 있는 싱글톤 개체처럼 동작하기 때문에 개인적으로 사용하지 않습니다.
DCI는 하나의 패러다임이기 때문에 각도가 없습니다.JS의 방법은 언어가 DCI를 지원하거나 지원하지 않습니다.소스 변환을 사용할 의향이 있으면 JS가 DCI를 잘 지원하지만 그렇지 않으면 몇 가지 단점이 있습니다.다시 말씀드리지만 DCI는 C# 클래스에 서비스가 있고 서비스도 아닌 것처럼 의존성 주입과는 관련이 없습니다.각도로 DCI를 하는 가장 좋은 방법은JS는 JS 방식으로 DCI를 수행하는데, 이는 애초에 DCI가 공식화된 방식과 매우 유사합니다.소스 변환을 수행하지 않으면 롤 메서드가 컨텍스트 외부에서도 객체의 일부가 되기 때문에 완전히 변환을 수행할 수 없지만 일반적으로 메서드 주입 기반의 DCI에 문제가 있습니다.DCI의 권위 있는 사이트인 fullOO.info 를 참조하면, 루비 실장에서도 메서드 인젝션이 사용되고 있는 것을 확인할 수 있습니다.또, DCI 의 상세한 것에 대하여는, 여기를 참조해 주세요.대부분의 경우 RUBY의 예이지만 DCI의 내용은 이와 무관합니다.DCI의 열쇠 중 하나는 시스템의 기능과 시스템이 분리된다는 것입니다.따라서 데이터 객체는 매우 멍청하지만 컨텍스트 역할 메서드에서 역할에 바인딩되면 특정 동작을 사용할 수 있습니다.역할은 단순히 식별자일 뿐이며, 식별자를 통해 개체에 액세스할 때 역할 메서드를 사용할 수 있습니다.역할 객체/클래스가 없습니다.메서드 주입에서는 역할 메서드의 범위가 설명과 정확히 일치하지는 않지만 종료됩니다.JS의 컨텍스트 예는 다음과 같습니다.
function transfer(source,destination){
source.transfer = function(amount){
source.withdraw(amount);
source.log("withdrew " + amount);
destination.receive(amount);
};
destination.receive = function(amount){
destination.deposit(amount);
destination.log("deposited " + amount);
};
this.transfer = function(amount){
source.transfer(amount);
};
}
다른 포스터에서 언급한 바와 같이, Angular는 모델링을 위한 기본 클래스를 즉시 제공하지는 않지만, 다음과 같은 여러 기능을 유용하게 제공할 수 있습니다.
- RESTful API와 상호 작용하여 새 개체를 만드는 메서드
- 모델 간의 관계 설정
- 백엔드를 유지하기 전에 데이터를 검증합니다.실시간 오류 표시에도 도움이 됩니다.
- 불필요한 HTTP 요청을 방지하기 위한 캐싱 및 느린 로드
- 스테이트 머신 훅(저장 전/후, 갱신, 작성, 신규 등)
이러한 모든 것을 잘 수행하는 라이브러리는 ngActiveResource(https://github.com/FacultyCreative/ngActiveResource))입니다.완전한 공개 - 이 라이브러리는 제가 작성했습니다.그리고 저는 이 라이브러리를 사용하여 여러 엔터프라이즈 규모의 애플리케이션을 구축했습니다.테스트도 잘 되어 있어 Rails 개발자에게 익숙한 API를 제공합니다.
저희 팀과 저는 계속해서 이 라이브러리를 적극적으로 개발하고 있으며, 더 많은 Angular 개발자들이 이 라이브러리에 기여하고 테스트하는 것을 보고 싶습니다.
오래된 질문이지만 Angular 2.0의 새로운 방향을 감안할 때 그 주제는 그 어느 때보다 적절하다고 생각합니다.베스트 프랙티스는 가능한 한 특정 프레임워크에 의존하지 않고 코드를 작성하는 것입니다.프레임워크 고유의 부품은 직접적 가치를 부가하는 부분만 사용하십시오.
현재 Angular 서비스는 차세대 Angular로 발전하는 몇 안 되는 개념 중 하나이기 때문에 모든 로직을 서비스로 이동한다는 일반적인 지침을 따르는 것이 현명할 것입니다.단, Angular 서비스에 직접 의존하지 않아도 디커플링된 모델을 만들 수 있다고 생각합니다.필요한 의존관계와 책임만을 가진 자기 억제형 객체를 작성하는 것이 아마도 바람직한 방법일 것입니다.또한 자동 테스트를 수행할 때 훨씬 더 쉽게 작업할 수 있습니다.요즘은 한 가지 책임만 지우는 게 유행이지만, 정말 말이 되네!
다음은 돔에서 오브젝트 모델을 분리하는 데 도움이 되는 패턴의 예입니다.
http://www.syntaxsuccess.com/viewarticle/548ebac8ecdac75c8a09d58e
주요 목표는 단위 테스트에서 보기와 같이 사용하기 쉽게 코드를 구성하는 것입니다.만약 당신이 그것을 달성한다면, 당신은 현실적이고 유용한 테스트를 작성할 수 있는 좋은 위치에 있습니다.
나는 이 블로그 포스트에서 그 문제를 해결하려고 노력했다.
기본적으로 데이터 모델링에 가장 적합한 곳은 서비스 및 공장입니다.다만, 데이터를 취득하는 방법이나 필요한 동작의 복잡성에 따라서는, 실장에는 여러가지 방법이 있습니다.Angular는 현재 표준 방법 또는 모범 사례가 없습니다.
이 투고에서는 $http, $resource 및 Resangular를 사용하는 세 가지 접근법에 대해 설명합니다.
각각에 몇 .getResult()
'이것'은 다음과 같습니다.
리스앵귤러 (간단한) :
angular.module('job.models', [])
.service('Job', ['Restangular', function(Restangular) {
var Job = Restangular.service('jobs');
Restangular.extendModel('jobs', function(model) {
model.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return model;
});
return Job;
}]);
$resource (복잡도가 높은 경우):
angular.module('job.models', [])
.factory('Job', ['$resource', function($resource) {
var Job = $resource('/api/jobs/:jobId', { full: 'true', jobId: '@id' }, {
query: {
method: 'GET',
isArray: false,
transformResponse: function(data, header) {
var wrapped = angular.fromJson(data);
angular.forEach(wrapped.items, function(item, idx) {
wrapped.items[idx] = new Job(item);
});
return wrapped;
}
}
});
Job.prototype.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return Job;
}]);
$180 (표준):
angular.module('job.models', [])
.service('JobManager', ['$http', 'Job', function($http, Job) {
return {
getAll: function(limit) {
var params = {"limit": limit, "full": 'true'};
return $http.get('/api/jobs', {params: params})
.then(function(response) {
var data = response.data;
var jobs = [];
for (var i = 0; i < data.objects.length; i ++) {
jobs.push(new Job(data.objects[i]));
}
return jobs;
});
}
};
}])
.factory('Job', function() {
function Job(data) {
for (attr in data) {
if (data.hasOwnProperty(attr))
this[attr] = data[attr];
}
}
Job.prototype.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return Job;
});
블로그 투고 자체는 각 접근방식을 사용하는 이유에 대한 자세한 설명과 컨트롤러에서 모델을 사용하는 방법의 코드 예시를 제공합니다.
AngularJS 데이터 모델: $http vs $resource vs resangular
Angular 2.0은 데이터 모델링에 대한 보다 강력한 솔루션을 제공하여 모든 사람이 같은 생각을 할 수 있도록 할 가능성이 있습니다.
언급URL : https://stackoverflow.com/questions/11112608/where-to-put-model-data-and-behaviour-tl-dr-use-services
'source' 카테고리의 다른 글
쉼표로 구분된 문자열을 json 어레이로 마이그레이션 (0) | 2022.11.14 |
---|---|
MySQL SELECT만 null 값이 아닙니다. (0) | 2022.11.14 |
"예쁜" 디렉토리 트리를 만들기 위한 ASCII 라이브러리? (0) | 2022.11.14 |
선택 쿼리 및 'order by' 절의 MySQL 문제 (0) | 2022.11.14 |
데이터베이스 sleeve로 인해 예외가 발생함 (0) | 2022.11.14 |