在Angular.js使用组合+依赖注入而不是继承

I ♥ Angular.js - Write Better, Flexible Code By Us

在Angular.js,您创建的每个对象(控制器,服务或工厂)是一个纯老javascript的对象(POJO)。POJO是小功能是独立的不继承任何其他对象 ,可轻松地测试和可扩展性。听起来可能不是很多,但是在大规模应用程序中实现去耦逻辑,这是非常重要的。

不要使用继承,继承导致代码耦合。

比如下面代码:


var Mammal = Backbone.Model.extend({
isAlive: true,

init: function () {
console.log('An animal is born');
},

eat: function (food) {
return 'omnomnom, I\'m eating: ' + food;
},

sleep: function () {
return 'zzzzz' ;
},

die: function () {
this.isAlive = false;
return 'I\'m dead!';
}
});

var Cat = Mammal.extend({
meow: function () {
return 'meow meow';
}
});

var Dog = Mammal.extend({
bark: function () {
return 'woof woof';
}
});

猫cat和狗dog继承Mammal,接下来如果需要扩展,比如猫狗是不能用来打猎吃的,如果我们需要豹panther和狼wolf,以及猎人杀死它们,可以看出,豹和狼虽然都是食肉特征,但是它属于不同的分类,添加这些食肉特征会导致重复代码,都有hunt和kill方法:

var Panther = Cat.extend({
hunt: function () {
return 'imma go search for food!';
},

kill: function (animal) {
animal.die();
return animal + ' is dead!';
}
});

var Wolf = Dog.extend({
hunt: function () {
return 'imma go search for food!';
},

kill: function (animal) {
animal.die();
return animal + ' is dead!';
}
});

根据达尔文的进化论,the traits that adapt to the environment the most make the organisms survive the best. 最适应环境的特征(trait)能让生物生存的最好。

许多生物体的特点可以是相似的,即使它们不属于相同的属或科。

使用组合方式实现如下:


var animals = angular.module('animals', []);

animals.factory('Mammal', function Mammal () {
this.init();

this.init = function () {
this.isAlive = true;
console.log('An animal is born');
};

this.eat = function (food) {
return 'omnomnom, I\'m eating: ' + food;
};

this.sleep = function () {
return 'zzzzz' ;
};

this.die = function () {
this.isAlive = false;
return 'I\'m dead!';
};
});

animals.service('meowingTrait', function () {
this.meow = function () {
return 'meow meow';
}
});

animals.service('barkingTrait', function () {
this.bark = function () {
return 'woof woof';
};
});

animals.service('huntingTrait', function () {
this.hunt = function () {
return 'imma go search for food!';
};

this.kill = function (animal) {
animal.die();
return animal + ' is dead!';
};
});

我们将豹和狼的动作特征trait以animals.service('huntingTrait',.)方式实现,这个特征trait独立成一个类,然后通过依赖注入将这个特征注入到具体实例中。如:

// Angular.js uses dependency injection to inject the traits you
// need for your animal.
animals.factory('Cat', function (meowingTrait) {
// use the meowing trait here.
});

animals.factory('Dog', function (barkingTrait) {
// use the barking trait here.
});

animals.factory('Panther', function (meowingTrait, huntingTrait) {
// meow or hunt, pick what you please!
});

animals.factory('Wolf', function (barkingTrait, huntingTrait) {
// bark or hunt, or do both!
});

这种方法一个明显的好处是,它使你的代码更好可测试,你可以创建一个物种,是一种混搭的各种性状triat,他们一定会如预期般运作的特点,只要有足够的单元测试。