dojo学习之2——使用 Dojo 掌握面向对象开发

使用 Dojo 模拟基于类的 OOP

在深入讨论 Dojo 的基于类的模拟之前,重要的是要注意到,到目前为止,Dojo 仍然是一个 JavaScript 库。Java 代码和 JavaScript 不是一回事;事实上,它们的差别很大。Dojo 并不试图迫使 JavaScript 像 Java 代码那样操作,相反,它允许 Java(和其他基于类的 OOP 语言)开发人员以一种他们熟悉的方式使用 JavaScript OOP,而底层结构仍然以一种原型方式工作。

使用 dojo.declare 创建类

要使用 Dojo 创建类,可以使用 dojo.declare 函数。现在,我们使用这个函数来创建一个 Car 类(见清单 9)。

清单 9. 使用 dojo.declare 创建一个 Car

dojo.declare("Car", null, {

});

var myCar = new Car();
console.log(myCar);

这是创建一个类并实例化该类的一个对象的基本 shell。dojo.declare 函数接受 3 个参数:

  1. 类名
  2. 类继承的超类
  3. 包含该类的所有属性和方法的一个对象
在清单 9 中的示例中,您声明了一个名为 Car 的类,它不从任何超类继承,也没有任何成员变量和方法。

如您所见,在 Dojo 中创建一个类将默认向从该类生成的任何对象赋予一些属性和方法。您现在的类不怎么有趣,因此,我们来添加一些属性和方法,以及一个构造器,就像上一小节中演示面向原型的方法时所做的那样(见清单 10)。

清单 10. 一个更完整的 Car
dojo.declare("Car", null, {
    reg_no: "",
    current_speed: 0,
    current_gear: 0,
    constructor: function(reg_no) {
        this.reg_no = reg_no;
    },
    accelerate: function(increment) {
        this.current_speed += increment;
    },
    decelerate: function(decrement) {
        this.current_speed -= decrement;
    },
    increaseGear: function() {
        this.current_gear++;
    },
    decreaseGear: function() {
        this.current_gear--;
    }
});

继承性和多继承性

清单 12. 使用 Dojo 创建 ATCar 子类
dojo.declare("ATCar", Car, {
    accelerate: function(increment) {
        this.inherited(arguments);
        if(increment >= 10) this.increaseGear();
    },
    decelerate: function(decrement) {
        this.inherited(arguments);
        if(decrement >= 10) this.decreaseGear();
    }
});

如清单 12 所示,子类中只提供所有被覆盖的或新的属性和方法(在本例中,您只是覆盖加速和减速方法以自动换挡)。Dojo 负责自动调用超类中的构造器。如果您需要添加一个构造器函数,可以向子类添加一个构造器函数,但您不必担心调用超类构造器,因为那将自动进行。您将注意到,在两个被覆盖的方法中,行 this.inherited(arguments) 都被调用,这将调用超类中的相同方法。这将使您避免重新编写代码来执行实际加速,只需像自动挡汽车那样方便换挡即可。

Dojo 还支持多继承性。多继承性允许一个子类从多个父类派生,从每个父类继承属性和方法。严格说来,只有一个父类被认为是超类(数组中的第一个),但每个父类的构造器都将被调用,调用顺序与这些父类在数组中的顺序一致。

为演示多继承性,我们以一个 Smartphone 为例,除了接打电话和收发文本消息外,它还有很多功能(见清单 14)。通常,它应该还有播放音乐、观看视频等功能。为简单起见,我们假设一个 Phone 能打电话,一个 MediaPlayer 能播放视频,而一个 Smartphone 具有上述两个功能。

清单 14. Dojo 中的多继承性
dojo.declare("Phone", null, {
    phone_number: "",
    minutes_remaining: 0,
    constructor: function(properties) {
        this.phone_number = properties.phone_number;
        this.minutes_remaining = properties.minutes_remaining;
        console.log("Phone "+this.phone_number+" powered on. You have 
"+this.minutes_remaining+" minute(s) remaining.");
    }
});

dojo.declare("MediaPlayer", null, {
    disk_space: 0,
    songs:[],
    constructor: function(properties) {
        this.disk_space = properties.disk_space;
        this.songs = properties.songs;
        console.log("Media Player powered on. You have "+this.songs.length+" songs,
with "+this.disk_space+" GB free space left.");
    }
});

dojo.declare("Smartphone", [Phone, MediaPlayer], {
    phone_id: "",
    constructor: function(properties) {
        this.phone_id = properties.phone_id;
        console.log("Smartphone ID "+this.phone_id+" boot up complete.");
    }
});

var songs = [
    {artist:"U2",title:"Vertigo"},
    {artist:"Coldplay",title:"Yellow"}
];

var myPhone = new Smartphone({
    <span style="color:#33CC00;">phone_number:"(555) 123-4567", 
    minutes_remaining: 60, 
    disk_space: 2.5, 
    songs: songs,
    phone_id: "4345FDFD7JAPO76"</span>
});

console.log(myPhone);

这里值得指出的第一点是: dojo.declare 是如何实现多继承性的。如您所见,一组类被传递,而不只是将父类作为第二个参数传递。这些父类的构造器将以它们在数组中的顺序自动被调用。重要的是要注意,如果每个父类构造器都接受不同的参数,那么 Dojo 将不能区分应该传递给每个构造器函数的参数。因此,如果您需要将不同的参数传递给不同的构造器,您应该在简单 JavaScript 中以 “键/值” 对的形式添加参数并在构造器中以那种方式使用它们。

使用 dojo.mixin 来改进多继承性示例

Dojo 提供了一个不错的工具函数 dojo.mixin,它允许您通过从左到右合并对象属性来混合对象(见清单 16)。

清单 16. 一个基本 dojo.mixin 示例
var objA = { a: 1, b: 2 };
var objB = { b: 3, c: 4 };
dojo.mixin(objA, objB);
console.log(objA);
最初在 objA 中被设置为 2b 属性已经被来自 objB 的值 3 所覆盖。而且, c 属性已经被添加。这个基本示例完成后,我们来看看如何在您的多继承性示例中使用 dojo.mixin

在上一个示例中创建 Phone 类时,您可能会回想起清单 17 中那个类的构造器中的两行。

清单 17. Phone 类构造器中的行
this.phone_number = properties.phone_number;
this.minutes_remaining = properties.minutes_remaining;

由于只有两行,这还不太麻烦,但如果行比较多该怎么办呢?必须以这种方式分配属性难道不是一件很令人痛苦的事吗?而这正是 dojo.mixin 函数真正有用的地方!使用下面的行替换这两行(以及MediaPlayerSmartphone 类中类似的行):dojo.mixin(this, properties);

结果与以前完全相同,但已经被传递到构造器的各个属性不会出现混乱。这很简洁,不是吗?

Dojo 中的打包和模块化开发

如果您来自一个 Java 开发环境,您可能更愿意遵循以下理念:不同的类应该驻留在不同的文件中,按照包进行分组。然后,当继承或其他目的需要时,再 “导入” 类,以确保它们仅在必要时才被加载。使用 JavaScript 时,没有这样的开箱即用打包和模块系统,但幸运的是,Dojo 提供了一个解决方案。

Dojo 通过 dojo.providedojo.require 函数提供了一个类似的打包系统。

清单 20. 在 Dojo 中打包类
dojo.provide("com.ibm.developerworks.dojoseries.Car");
dojo.declare("com.ibm.developerworks.dojoseries.Car", null, {
	//Car class code goes here
});

清单 21. 在 Dojo 中导入类
dojo.provide("com.ibm.developerworks.dojoseries.ATCar");
dojo.require("com.ibm.developerworks.dojoseries.Car");
dojo.declare("com.ibm.developerworks.dojoseries.ATCar", 
   com.ibm.developerworks.dojoseries.Car, {
	//ATCar class code goes here
});

尽管从技术上讲类名可以与 dojo.provide 语句中提供的路径不同(注意,使用 dojo.require 进行的任何类加载必须使用 dojo.provide 中设置的完全限定路径),但我们强烈建议不要这样做,因为这样只会导致混乱。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值