Javascript中的Trait與程式碼重用
我們知道,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);
相關文章
- WPF中的命令模式:打造清晰、可重用的程式碼利器模式
- 程式碼質量第 2 層 - 可重用的程式碼
- Java 繼承與多型:程式碼重用與靈活性的巧妙結合Java繼承多型
- Java 抽象類與方法:實現安全性與程式碼重用Java抽象
- scala中的TraitAI
- 關於在web project專案中的程式碼重用問題討論WebProject
- C# 程式碼中呼叫 Javascript 程式碼段以提高應用程式的配置靈活性(使用 Javascript .NET 與 Jint)C#JavaScript
- 含有SilverLight專案的程式碼重用
- 提高Java程式碼可重用性的三個措施Java
- Google Inbox 是如何跨平臺重用程式碼的?Go
- 過去兩年中我對程式碼重用的體驗
- 提高Java程式碼可重用性的三個措施 (轉)Java
- 重用其他程式庫
- 4、 oracle 10g中的密碼策略---密碼重用規則Oracle 10g密碼
- PHP中Trait特性PHPAI
- 企業中的低程式碼與無程式碼
- Cordova外掛中JavaScript程式碼與Java的互動細節介紹JavaScript
- PHP中Trait的使用總結PHPAI
- PHP中的trait方法衝突PHPAI
- Rust 中的 Trait 是什麼RustAI
- 一些 JavaScript 中的程式碼小技巧JavaScript
- JavaScript中的繼承及實現程式碼JavaScript繼承
- 怎麼消除JavaScript中的程式碼壞味道JavaScript
- BCB中用Sender引數實現程式碼重用 (轉)
- AndroidWebView與JavaScript程式碼互動AndroidWebViewJavaScript
- 52. 模版和設計元素——Lotus Notes的程式碼重用
- C#程式碼與javaScript函式的相互呼叫C#JavaScript函式
- BCB中用Sender實現程式碼重用(糾正篇) (轉)
- 如何組織大型JavaScript應用中的程式碼?JavaScript
- 常用的JavaScript程式碼JavaScript
- MyBatis資料持久化 SQL複用(可重用的 SQL 程式碼段)MyBatis持久化SQL
- JavaScript中的+0與-0JavaScript
- # JavaScript中的 || 與 && 運算子JavaScript
- Javascript中“==”與“===”的區別JavaScript
- javascript刪除陣列中的重複元素程式碼JavaScript陣列
- 如何在 Laravel 中靈活的使用 TraitLaravelAI
- oracle資料庫中索引空間的重用Oracle資料庫索引
- 淺拷貝與深拷貝程式碼(javascript)JavaScript