Trait and code reuse in Javascript

Source: Internet
Author: User
Tags traits

We know that the most common way of code reuse in OOP is through inheritance. However, inheritance has some disadvantages. The most important one is that inheritance is an isa relationship, the relationship between parent and child classes is too close. For JAVA, only single inheritance is supported, so that code copying is not necessary in many cases.

For example, suppose we want to create an animal. The bottom layer is an Animal object, which contains cats and dogs. Then there are cats and tigers under the CAT. Dogs and wolves are under the inspecies. A cat can be miao, a dog can be called, and a tiger and a wolf can both be used for hunting. The problem arises because the hunting feature is available to both tigers and wolves, but tigers and cats inherit from each other, wolves have inherited from dogs, and they cannot inherit from them to gain the ability to hunt.

Let's take a look at how Trait solves this problem. Trait looks like a class on the surface. It has attributes and methods, but it must be attached to a class to work. Multiple Traits can be combined into one Trait. If the attributes or methods in different Traits conflict, you can choose to rename the attributes to determine the conflict. If the conflict does not have a resolution, the combination of Traits will throw an exception.

As described above, we define hunting as a Trait, and then integrate Trait when building tiger and Wolf classes. In this way, tigers and wolves will be able to hunt.

Due to restrictions of the Java language, there is no gorgeous way to implement Trait. Let's take a look at how the prototype-based Javascript language implements Trait. This actually proves from one side that prototype-based Javascript is more flexible and powerful For OOP than class-based Java. To reduce the code size, I use the JS library light-traits. Because the full implementation of a Traits library is beyond the scope of this article.

 
 
  1. var util = require('util'); 
  2. var Trait = require('light-traits').Trait; 
  3. var expect = require('chai').expect; 
  4. var _ = require('lodash'); 
  5. function inherits(constructor, parentConstructor, trait, properties) { 
  6.   util.inherits(constructor, parentConstructor); 
  7.   if (properties !== undefined) 
  8.     _.extend(constructor.prototype, properties); 
  9.   if (trait !== undefined) 
  10.     constructor.prototype = trait.create(constructor.prototype); 
  11.  
  12. function Animal() {} 
  13. Animal.prototype = { 
  14.   isAlive: true, 
  15.   eat: function (food) { 
  16.     console.log("omnomnom, I'm eating: " + food); 
  17.   }, 
  18.   sleep: function () { 
  19.     console.log('zzzz'); 
  20.   }, 
  21.   die: function () { 
  22.     this.isAlive = false; 
  23.     console.log("I'm dead"); 
  24.   } 
  25. }; 
  26.  
  27. function CatFamily() {} 
  28. inherits(CatFamily, Animal); 
  29. function DogFamily() {} 
  30. inherits(DogFamily, Animal); 
  31.  
  32. var TMeow = Trait({ 
  33.   meow: function () { 
  34.     console.log('meow meow'); 
  35.   } 
  36. }); 
  37. function Cat() {} 
  38. inherits(Cat, CatFamily, TMeow); 
  39.  
  40. var cat = new Cat(); 
  41. cat.meow(); 
  42.  
  43. var TBark = Trait({ 
  44.   bark: function () { 
  45.     console.log('woof woof'); 
  46.   } 
  47. }); 
  48. function Dog() {} 
  49. inherits(Dog, DogFamily, TBark); 
  50.  
  51. var dog = new Dog(); 
  52. dog.bark(); 
  53.  
  54.  
  55. var THunt = Trait({ 
  56.   huntCount: 0, 
  57.   hunt: function () { 
  58.     console.log('looking for food', this.huntCount++, 'times'); 
  59.  
  60.   }, 
  61.   kill: function (animal) { 
  62.     animal.die(); 
  63.     console.log('I killed animal'); 
  64.   } 
  65. }); 
  66.  
  67. function Tiger() {} 
  68. inherits(Tiger, CatFamily, THunt, { 
  69.   roar: function () { 
  70.     console.log("roar...roar..."); 
  71.   } 
  72. }); 
  73.  
  74. var tiger = new Tiger(); 
  75. expect(tiger).to.be.instanceOf(CatFamily); 
  76. expect(tiger).to.have.property('hunt'); 
  77. expect(tiger).to.have.property('kill'); 
  78. expect(tiger).to.not.have.property('meow'); 
  79. expect(tiger.isAlive).to.be.equal(true); 
  80. tiger.hunt(); 
  81. tiger.eat('meat'); 
  82. tiger.roar(); 
  83.  
  84. function Wolf() {} 
  85. inherits(Wolf, DogFamily, Trait.compose(TBark, THunt)); 
  86.  
  87. var wolf = new Wolf(); 
  88. expect(wolf).to.be.instanceOf(DogFamily); 
  89. expect(wolf).to.have.property('hunt'); 
  90. expect(wolf).to.have.property('kill'); 
  91. expect(wolf).to.have.property('bark'); 
  92. expect(wolf.isAlive).to.be.equal(true); 
  93. wolf.bark(); 
  94. wolf.hunt(); 
  95. wolf.hunt(); 
  96. wolf.sleep(); 
  97. wolf.kill(cat); 
  98. expect(cat.isAlive).to.be.equal(false); 
  99. expect(wolf.huntCount).to.be.equal(2); 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.