Javascript中的Trait与代码重用
Javascript中的Trait与代码重用
来源 http://www.ituring.com.cn/article/64103
我们知道,OOP中最普遍的代码重用方式是通过继承,但是,继承有一些缺点,其中最为主要的是继承是一种isa关系,父子类之间的关系太过紧密,而对于像JAVA这门语言而言,只能支持单继承,使得很多时候不能不进行代码拷贝这样的事情。
举个例子,假设我们要建模动物。最底层是一个Animal对象,下面有猫科,犬科。然后猫科下有猫,老虎。犬科下有狗和狼。 猫能够miao,狗能够叫,老虎和狼都能够狩猎,这个时候问题来了,由于狩猎这个特性是老虎和狼都有的,但是老虎以及从猫科继承,狼已经从犬科继承,它们都已经无法通过继承来获得狩猎这个能力了。
让我们来看看Trait如何来解决这个问题。 Trait从表面上看和一个类很类似,有属性和方法,但是它必须依附于一个类才能起作用。同时多个Traits可以组合成一个Trait。如果不同的Traits中属性或者方法有冲突的话,可以选择重命名属性的方法来决议冲突。如果冲突没有决议的话,组合Traits会抛出异常。
这样,类层次仍然像前面描述的一样,我们把狩猎定义为一个Trait,然后在构建老虎和狼的类的时候把Trait融入进去。这样老虎和狼就获得了狩猎的能力了。
由于Java语言的限制,没有一种华丽的方法来实现Trait。让我们来看看基于原型的Javascript语言如何实现Trait。这个其实从一个侧面证明基于原型的Javascript和基于类的Java相比,对于OOP而言更加灵活和强大。为了缩减代码的大小,这里我使用light-traits这个JS库。因为完整实现一个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);
Javascript中的Trait与代码重用的更多相关文章
- javascript 中的 let 作用域
let 声明了一个块级域的局部变量,并且可以给它一个初始化值. 语法EDIT let var1 [= value1] [, var2 [= value2]] [, ..., varN [= value ...
- 浅谈JavaScript中的定时器
引言 使用setTimeout()和setInterval()创建的定时器可以实现很多有意思的功能.很多人认为定时器是一个单独的线程(之前我也是),但是JavaScript是运行在单线程环境中的,而定 ...
- JavaScript中的位置屬性
屏幕中的位置(直接使用,無需前綴): screenLeft.screenTop:除了火狐都支持 screenX.screenY: 窗口的大小(谷歌的inner=outer,直接使用,無需前綴): in ...
- JavaScript中的this指向规则
首先,JavaScript的this指向问题并非传说中的那么难,不难的是机制并不复杂,而被认为不好理解的是逻辑关系和容易混淆的执行上下文.这篇博客也就会基于这两个不好理解的角度来展开,如要要严格的来对 ...
- JavaScript 中对变量和函数声明提前的演示样例
如题所看到的,看以下的演示样例(能够使用Chrome浏览器,然后F12/或者右键,审查元素.调出开发人员工具,进入控制台console输入)(使用技巧: 控制台输入时Shift+Enter能够中途代码 ...
- 漫谈JavaScript中的提升机制(Hoisting)
前言 刚接触到JavaScript的时候,便知道JavaScript是按顺序执行的,是如浏览器的解析DOM树一样的流程,解析DOM结构的时候,如果遇到JS脚本或者外联脚本便会停止解析,继续下载脚本之后 ...
- JavaScript 中的执行上下文和执行栈
JavaScript - 原理系列 在日常开发中,每当我们接手一个现有项目后,我们总喜欢先去看看别人写的代码.每当我们看到别人写出很酷的代码的时候,我们总会感慨!写出这么优美而又简洁的代码的兄弟到 ...
- 【优雅代码】深入浅出 妙用Javascript中apply、call、bind
这篇文章实在是很难下笔,因为网上相关文章不胜枚举. 巧合的是前些天看到阮老师的一篇文章的一句话: “对我来说,博客首先是一种知识管理工具,其次才是传播工具.我的技术文章,主要用来整理我还不懂的知识.我 ...
- HTML中使用javascript解除禁止input输入框代码:
转:表单中Readonly和Disabled的区别 参考资料: disabled和readonly区别: 参考博文1地址:http://blog.csdn.net/symgdwyh/article/d ...
随机推荐
- Lodop 动态加载模板,动态加载数据
最近需要使用Lodop打印控件,所以就研究了一下,期间从网上找了诸多的东西,基本全是对HTML进行打印的,没有找到我想要的,就只好自己动手丰衣足食. 这篇文章主要讲述的是Lodop与数据的结合使用,官 ...
- 转自知乎(JAVA后台开发可以纯粹用JAVA SE吗?)
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:巴多崽链接:http://www.zhihu.com/question/29663744/answer/45154839来源: ...
- java中堆栈的功能作用 以及區別(搜集)
1.用new创建的对象在堆区,函数中的临时变量在栈区,Java中的字符串在字符串常量区. 2.栈:存放进本数据类型的数据和对象的引用,但对象本身不存在栈中,而是存放在堆中. 堆:存放new产生 ...
- es6函数的rest参数和拓展运算符(...)的解析
es6的新特性对函数的功能新增加了rest参数和...的拓展运算符.这是两个什么东西呢? 先来看一个问题:如何获取一个函数除了定义的参数之外的其他参数?传统的做法是借助函数的arguments关键字来 ...
- 初识Hibernate之理解持久化类
上一篇文章我们简单介绍了Hibernate相关的一些最基本的文件及其作用,并在最后完整的搭建了Hibernate的运行环境,成功的完成了与数据库的映射.但是至于其中的一些更加细节的地方并没有 ...
- P1035
P1035 时间限制: 1 Sec 内存限制: 128 MB提交: 87 解决: 36[提交][状态][讨论版] 题目描述 给出一张n*n(n< =100)的国际象棋棋盘,其中被删除了一些点 ...
- Android02-控件
在android studio中,新建一个module时布局文件中就会默认带一个TextView,里面显示着一句话:Hello World ! 布局中通常放置的是android控件,下面介绍几个an ...
- python2.7 使用super关键词 报错 TypeError: must be type, not&n
错误试验代码: class Base(): def meth(self): print "i'm base" class Derived(Base): def meth(self) ...
- HDU1251统计难题(水字典树)
统计难题 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others) Total Subm ...
- IsKeyboardFocused -- 键盘焦点
<Trigger Property="IsKeyboardFocused" Value="true"> <!--<Setter Prop ...