知っている、コードの再利用の最も一般的な方法でOOPは、継承を介してですが、継承にはいくつかの欠点があり、その中で最も重要なのは、継承はisaの関係であり、親と子のクラス間の関係が近すぎると、JAVAなどの言語については、1つの継承をサポートすることができます、これは多くの時間は、このようなことをコピーするコードなしで行うことはできません。
例として、動物をモデリングするとします。一番下にAnimalオブジェクトがあり、その下にFelineファミリーとCanineファミリーがあります。そしてネコ科の下にはネコとトラ。イヌ科の下にはイヌとオオカミがいます。 問題は、狩りはトラもオオカミも持っている機能ですが、トラはネコ科から、オオカミはイヌ科から受け継いだものなので、遺伝で狩りの能力を得ることはできないということです。
Traitがこの問題をどのように解決するか見てみましょう。 Trait は、プロパティとメソッドを持つという点ではクラスと表面的には似ていますが、機能するためにはクラスにアタッチする必要があります。複数の Trait を同時に 1 つの Trait にまとめることができ、異なる Trait のプロパティまたはメソッド間で競合が発生した場合は、競合を解決するためにプロパティのメソッド名を変更することができます。競合が解決されない場合、結合された Traits は例外をスローします。
このようにして、クラス階層は前述のように狩猟を特質として定義したまま、トラとオオカミのクラスを構成するときに特質を組み入れます。このようにして、虎と狼は狩りの能力を得ます。
Java言語の制限により、traitを実装する派手な方法はありません。そこで、traitをプロトタイプベースのJavascript言語でどのように実装できるかを見てみましょう。実際に、プロトタイプベースのJavascriptは、クラスベースのJavaよりもOOPに対して柔軟で強力であることを証明しています。コードサイズを小さくするために、light-traitsライブラリを使用しています。Traitsライブラリの完全な実装はこの記事の範囲を超えているからです。
var util = require('util');
var Trait = require('light-traits').Trait;
var expect = require('chai').expect;
var _ = require('lodash');
function inherits(constructor, parentConstructor, trait, properties) {
util.inherits(constructor, parentConstructor);
if (properties !== undefined)
_.extend(constructor.prototype, properties);
if (trait !== undefined)
constructor.prototype = trait.create(constructor.prototype);
}
function Animal() {}
Animal.prototype = {
isAlive: true,
eat: function (food) {
console.log("omnomnom, I'm eating: " + food);
},
sleep: function () {
console.log('zzzz');
},
die: function () {
this.isAlive = false;
console.log("I'm dead");
}
};
function CatFamily() {}
inherits(CatFamily, Animal);
function DogFamily() {}
inherits(DogFamily, Animal);
var TMeow = Trait({
meow: function () {
console.log('meow meow');
}
});
function Cat() {}
inherits(Cat, CatFamily, TMeow);
var cat = new Cat();
cat.meow();
var TBark = Trait({
bark: function () {
console.log('woof woof');
}
});
function Dog() {}
inherits(Dog, DogFamily, TBark);
var dog = new Dog();
dog.bark();
var THunt = Trait({
huntCount: 0,
hunt: function () {
console.log('looking for food', this.huntCount++, 'times');
},
kill: function (animal) {
animal.die();
console.log('I killed animal');
}
});
function Tiger() {}
inherits(Tiger, CatFamily, THunt, {
roar: function () {
console.log("roar...roar...");
}
});
var tiger = new Tiger();
expect(tiger).to.be.instanceOf(CatFamily);
expect(tiger).to.have.property('hunt');
expect(tiger).to.have.property('kill');
expect(tiger).to.not.have.property('meow');
expect(tiger.isAlive).to.be.equal(true);
tiger.hunt();
tiger.eat('meat');
tiger.roar();
function Wolf() {}
inherits(Wolf, DogFamily, Trait.compose(TBark, THunt));
var wolf = new Wolf();
expect(wolf).to.be.instanceOf(DogFamily);
expect(wolf).to.have.property('hunt');
expect(wolf).to.have.property('kill');
expect(wolf).to.have.property('bark');
expect(wolf.isAlive).to.be.equal(true);
wolf.bark();
wolf.hunt();
wolf.hunt();
wolf.sleep();
wolf.kill(cat);
expect(cat.isAlive).to.be.equal(false);
expect(wolf.huntCount).to.be.equal(2);





