Demeter定律和角度控制器DI

时间:2014-12-18 05:01:35

标签: angularjs law-of-demeter

我正在阅读http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf(请参阅,尤其是第8页)并观看Misko的Youtube视频,编写可测试的代码,并且我发现Angular的方式DI会强迫您违反Demeter法则。

从PDF中简化,一个违反Demeter法则的Java构造函数的例子:

class AccountView {
  boolean isAdmin;
  AccountView(AccountService) {
    isAdmin = AccountService.getCurrentUser().getProfile().isAdmin();
  }
}

因为该类只需要用户是否为admin,而不是AccountService。

似乎Angular强迫你用它的DI打破Demeter的规律。我看不到以下的替代方案:

.controller('AccountServiceController', 
  ['AccountService', 
  function(AccountService) {
    this.user = AccountService.getCurrentUser().getProfile().isAdmin();
  }]
);

如果这是一个控制器,控制器是具有解析参数的路由器,我们可以注入一个用户,但不适用于一般情况。有什么想法吗?请注意,我假设只有AccountService是一个单例,并且每个后续对象都是一个实例(并且不能是DI)。

1 个答案:

答案 0 :(得分:1)

我不确定您提供的Angular示例或Angular DI一般是否违反了demeter法则。角度依赖注入允许您编写非常可测试的代码。

假设真实AccountService.getCurrentUser();是一个非常昂贵的网络操作。我们绝对不想在测试中调用此方法。使用Angular的依赖注入,我们可以模拟AccountService,因此我们不必调用真实的。{/ p>

让我们为AccountServiceController编写一个测试:

控制器

.controller('AccountServiceController', 
  ['$scope', 'AccountService', 
  function($scope, AccountService) {
    $scope.user = AccountService.getCurrentUser();
  }]
);

测试

describe('AccountServiceController function', function() {

  describe('AccountServiceController', function() {
    var $scope;

    beforeEach(module('myApp'));

    beforeEach(inject(function($rootScope, $controller) {
      $scope = $rootScope.$new();
      $controller('AccountServiceController', {
        $scope: $scope
        AccountService: {
          getCurrentUser: function () {
            return {
              name: 'Austin Pray',
              id: 1111
            };
          }
        }
      });
    }));

    it('should get the current user', function() {
      expect(typeof $scope.user.name).toBe('string');
    });
  });
});

我们避免了昂贵的网络操作,并且控制器没有以任何方式耦合到AccountService的内部。