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 ...
随机推荐
- 用static声明的函数和变量小结
static 声明的变量在C语言中有两方面的特征: 1).变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值.这一点是它与堆栈变量和堆变量的区别. 2).变量用static ...
- mysql 存储引擎介绍1
1.1 存储引擎的使用 数据库中的各表均被(在创建表时)指定的存储引擎来处理. 服务器可用的引擎依赖于以下因素: MySQL的版本 服务器在开发时如何被配置 启动选项 为了解当前服务器中有哪些存储引 ...
- java 基础语法 1
一.标识符 二.关键字 三.JAVA基础数据类型 3.1. java常量 3.2. java变量 从本质上来讲,变量其实是内存里面的一小块区域,一个程序在运行的时候,实际上这个程序是位于内存里面,然后 ...
- 初识 JShell
Java9 现在吵得热火朝天,赶紧顺势学习一波喽! JDK9 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk9-dow ...
- WebSocket 开发模拟客户端与有游戏服务器通信
WebSocket 客户端测试功能 websocket是有标准的通信协议,在h2engine服务器引擎中继承了websocket通信协议,使用websocket通信协议的好处是很多语言或框架都内置了w ...
- 快速搭建应用服务日志收集系统(Filebeat + ElasticSearch + kibana)
快速搭建应用服务日志收集系统(Filebeat + ElasticSearch + kibana) 概要说明 需求场景,系统环境是CentOS,多个应用部署在多台服务器上,平时查看应用日志及排查问题十 ...
- 分享基于分布式Http长连接框架--代码模型
好的代码应该是方便客户端使用,代码能够自描述,规范化,大众标准化. 而且我相信代码也是有生命的,需要不断的维护它,你以什么样的态度对待它,它就会以同样的态度回敬你,所以在写代码前,先摆好自己的态度(一 ...
- hdu4705 Y 2013 Multi-University Training Contest 10
Y Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submis ...
- 我的第一个python web开发框架(5)——开发前准备工作(了解编码前需要知道的一些常识)
中午吃饭时间到了,小白赶紧向老菜坐的位置走过去. 小白:老大,中午请你吃饭. 老菜:哈哈...又遇到问题了吧,这次得狠狠宰你一顿才行. 小白:行行行,只要您赏脸,米饭任吃,嘻嘻,我们边走边聊. ... ...
- DAO与DTO
DAO叫数据访问对象(data access object) DTO是数据传输对象(data transfer object) DAO通常是将非对象数据(如关系数据库中的数据)以对象的方式操纵.(即一 ...