当把模型数据和行为? [TL; 博士; 使用的服务] 当把模型数据和行为? [TL; 博

2019-06-02 13:54发布

我与AngularJS工作我的最新项目。 在文档和教程的所有模型数据被置于控制器的范围。 据我所知,是具有在那里为可用于控制器,因此内相应的视图。

不过,我不认为该模型实际上应该有实现的。 这可能是复杂的,有例如私有属性。 另外一个可能想重新使用它在另一个环境/应用程序。 把什么东西都往控制器完全打破了MVC模式。

这同样适用于任何型号的行为属实。 如果我会使用DCI架构和独立的行为,从数据模型,我会介绍其他对象持有的行为。 这将通过引入角色和情境来完成。

当然,模型数据和行为可以用普通的JavaScript对象或任何“类”模式来实现。 但是,这将是AngularJS办法做到这一点? 使用服务?

所以它归结为这样一个问题:

如何实现从控制器分离机型,下面AngularJS最佳做法?

Answer 1:

如果你想通过多个控制器可用的东西,你应该使用服务。 这里有一个简单的人为的例子:

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
}


Answer 2:

目前,我想要这种模式,这虽然不是DCI,提供了一个经典的服务/模型去耦(与服务谈话Web服务(又名模型CRUD)和模型定义对象的属性和方法)。

注意每当模型对象需要方法对自己的工作性质,我只能用这种方式,我可能会到处使用(如改进的getter / setter方法)。 我主张为每个服务系统这样做。

编辑:我曾经认为这种模式会违背“角模型是普通的老式JavaScript对象”的口号,但现在看来,我认为这个模式是完全正常的。

EDIT(2):为了更清楚,我使用模型的类只对因子简单getter / setter方法(例如:在视图模板中使用)。 对于大的业务逻辑,我建议使用单独的服务(s)表示,“知道”的模式,而是从它们处于分离状态,只有包括业务逻辑。 调用它,如果你想有一个“业务专家”服务层

服务/ 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
}

模型/ Element.js(使用angularjs厂,对象创建制造)

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;
});


Answer 3:

该Angularjs文件明确规定:

不像许多其他框架角使得该模型没有限制或要求。 有没有类继承或访问或改变模型特殊的存取方法。 该模型可以是原始的,对象的散列,或完整的对象类型。 总之该模型是一个普通的JavaScript对象。

因此,这意味着这取决于你如何定义一个模型。 这是一个简单的JavaScript对象。

我个人不会用角服务,他们被认为表现得像你可以使用,例如,保持在你的应用程序的全局状态单一对象。



Answer 4:

DCI是一个范例,因此有做的​​不angularJS方式,无论是语言支持DCI或者没有。 JS支持DCI相当好,如果你愿意用源变换,并与一些缺点,如果你不是。 同样DCI有没有更多的是依赖注入不如说是一个C#类和具有绝对不是一个服务无论是。 所以,我们要做的DCI与angulusJS最好的办法是做DCI的JS的方式,这是非常接近DCI是如何在第一时间制定。 除非你做源变换,你将不能够完全做到这一点,因为角色的方法会更外的上下文对象的一部分,但通常是用注射的方法根据DCI的问题。 如果你看一下fullOO.info权威网站DCI你可以看看在Ruby实现他们也使用方法注入,或者你可以在看看这里对DCI的更多信息。 这主要是与红宝石的例子,但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);
   };
}


Answer 5:

这篇文章车型在AngularJS可能有帮助:

http://joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/



Answer 6:

正如其他海报指出,角为造型没有超出现成的基类,但可以有效地提供几个功能:

  1. 对于一个RESTful API进行交互和创建新的对象方法
  2. 建立模型之间的关系
  3. 持续到后端之前验证数据; 也可用于实时显示有用的错误
  4. 缓存和延迟加载,以保持作出浪费HTTP请求
  5. 状态机钩(前/后保存,更新,创造,新等)

完成所有的这些东西一个库井ngActiveResource( https://github.com/FacultyCreative/ngActiveResource )。 充分披露 - 我写这个库 - 我已经在构建一些企业级应用程序成功地使用它。 这是很好的测试,并规定应该熟悉到Rails开发者的API。

我和我的团队继续积极发展这个图书馆,我很乐意看到更多角度的开发作出贡献和作战测试。



Answer 7:

一个旧的问题,但我认为该主题的相关性更强比以往给出的角2.0的新方向。 我会说最好的做法是写用尽可能少的依赖代码上尽可能的特定框架。 只有使用它增加了直接的价值框架特定部分。

目前,它似乎是一个角服务的几个概念,这将使它的下一代角一个,所以它可能是明智的遵循所有逻辑转移到服务的一般准则。 但是,我认为,你可以退耦模型即使没有角服务的直接依赖。 只有必要的依赖和责任创建自我包含的对象可能是要走的路。 这也使得生活在做自动化测试的时候轻松了不少。 单责任是一个时髦的工作,这些天,但它确实让很多的感觉!

这里是我考虑好了从DOM解耦的对象模型图案的例子。

http://www.syntaxsuccess.com/viewarticle/548ebac8ecdac75c8a09d58e

一个关键的目标是构造代码的方式,使得它也很容易从一个单元测试从视图中使用。 如果你做到这一点,你能很好地写现实和有用的测试。



Answer 8:

我试图解决的是准确的问题在这个博客帖子 。

基本上,数据建模最好的家是在服务和工厂。 但是,这取决于你如何获取你的数据和你所需要的行为的复杂性,有很多不同的方式去实现。 角目前还没有标准的方法或最佳实践。

岗位涵盖了三种方法,使用$ HTTP,$ 资源Restangular

这里的每个一些示例代码,使用自定义getResult()的工作模型的方法:

Restangular(易peasy):

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;
  }]);

$资源(稍微令人费解):

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;
    }]);

$ HTTP(铁杆):

angular.module('job.models', [])
    .service('JobManager', ['$q', '$http', 'Job', function($q, $http, Job) {
        return {
            getAll: function(limit) {
                var deferred = $q.defer();

                $http.get('/api/jobs?limit=' + limit + '&full=true').success(function(data) {
                    var jobs = [];
                    for (var i = 0; i < data.objects.length; i ++) {
                        jobs.push(new Job(data.objects[i]));
                    }
                    deferred.resolve(jobs);
                });

                return deferred.promise;
            }
        };
    }])
    .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 $资源VS Restangular

有角2.0可能会提供一个更强大的解决方案,数据建模是得到大家在同一页上。



文章来源: Where to put model data and behaviour? [tl; dr; Use Services]