原创作者: Ivan_Pig
阅读:1496次
评论:0条
更新时间:2011-05-26
Lesson 8: Data Binding and Triggers
目录
- 绑定概述
- 绑定和对象
- 绑定和方法
- 绑定序列
- 替换触发器
-绑定的概念
bind关键字将目标变量的值和一个范围表达式联系(bound expression)起来。范围表达式可以是基本类型,一个对象,方法的返回值或者一个表达式的返回值。
下面的章节将一个个的举例。
-绑定和对象
现实中,大部分情况下,你要使用数据绑定,来同步GUI和它的数据
(GUI是 《Building GUI Applications with JavaFX》的主题; 下面我们演示的是简单的非GUI例子)
我们从简单的开始:下面的脚本中,将变量x绑定到了变量y上,改变x的值,然后打印出y的值。由于变量被绑定了,y的值会自动的更新为新值。
注意,我们是用def声明的变量y。这样的话,能够阻止直接修改y的值!(y的值允许以绑定的方式修改)在下面的绑定对象的例子中,你应该以相同的方式来绑定。
当你修改myStreet的值的时候,address对象里的street变量的值也会随之改变。
注意,myStreet值的改变将导致一个新的Address对象被创建,并且这个对象被赋予了address变量。如果想改变值,但是不要新创建一个新的Address对象,直接在实例变量上进行绑定。
如果你已明确的对实例变量进行了绑定,那么你可以省略第一个bind(Address前面的那个bind)
-绑定和方法
前面已经讨论过方法了,但是你还要学习一下bound functions 和non-bound functions之间的差别。
下面的方法,它创建并返回一个Point对象:
这就是所谓的bound function,因为它以bound关键字开头。
Note: bound关键字不是替代bind关键字的。在下面的例子里面,将会同时使用bound和bind.
接着,我们添加一些代码来调用这个方法并测试绑定:
输出:
3.0
10.0
20.0
我们来分析这段代码:
代码:
初始化变量myX和myY为3.0。这些值将已参数的方式传给makePoint方法。makePoint方法前面的bind关键字,将新创建的Point对象pt绑定到了makePoint方法的返回值上。(
The bind keyword, placed just before the invocation of makePoint, binds the newly created Point object (pt) to the outcome of the makePoint function.)[这里字面意思是pt绑定到了makePoint的返回值上去了,我理解的是返回值绑定到pt上去。]
下一段代码:
修改myX的值为10.0然后打印pt.x。pt.x也将输出10.0
最后一段代码:
修改scale的值并打印出pt.x。现在pt.x的值是20.0,如果我们将方法前面的bound关键字去掉(就变成了non-bound function),输出将会是:
这是因为non-bound functions只有在它的参数发生改变的时候才会重新执行。而scale并不是方法的参数,所以改变scale的值不会对方法产生影响。
-绑定序列
你还可以在表达式上使用bind。要解释这一点,让我们先来定义两个序列并打印他们的值。
seq1有10个项(1到10).seq2也有10个项,并且和seq1的值相等,但是我们给每项都乘以了2,所以值将是seq1的两倍。
输出:
第一个序列:
1
2
3
4
5
6
7
8
9
10
第二个序列:
2
4
6
8
10
12
14
16
18
20
只要在for关键字前面加上bind关键字,我们就能将两个序列绑定了。
现在的问题就是“如果seq1里面发生改变了,seq2里面的所有项或部分项会有影响吗?”我们可以在seq1的末尾插入一项(值为11)来测试一下。
输出:
第一列:
1
2
3
4
5
6
7
8
9
10
11
第二列:
2
4
6
8
10
12
14
16
18
20
22
输出显示了在seq1中插入11后,对seq2里的前面10项并没有产生影响,而是自动的加到了seq2的后面,并且值是22.
-替换触发器(replace trigger)
替换触发器是一段特殊的代码,它和变量关联,并且只要变量的值发生改变就会执行。下面的例子展示了基本的语法:定义了一个password变量并和一个替换触发器关联,当password改变的时候,触发器打印出password的新值。
输出:
ALERT! Password has changed!
Old Value:
New Value: foo
ALERT! Password has changed!
Old Value: foo
New Value: bar
这里触发器被触发了两次:第一次,当password被初始化为"foo"的时候,以及第二次当值变成"bar"时。
注意,oldValue变量持有触发器执行前变量的值。你能够任意命名此变量,我们使用oldValue只是因为它比较直观。
Lesson 9: Writing Your Own Classes
目录
- 例子:Customer
- 从其他类继承
-例子:Customer
在Writing Scripts章节,你学会了如何使用对象。但是,当时我们是让你去下载了.class文件,以使编译器知道怎么去创建Address和Customer对象。在下面的例子里面,我们重新来看代码,新增缺少的类定义,以保证所有的代码都能通过编译。
如果你已经掌握了变量和方法,那么这段代码你应该很容易理解。Address类声明了street, city, state, and zip实例变量,且都是String类型。Customer也声明了一些实例变量还有一些方法来打印他们的值。因为这些变量和方法都是在类里面声明的,所以在你创建的任意的Address和Customer类的实例都能够访问到他们。
-从其他类继承
你还能创建一个类,并从其他类里面继承变量和方法。例如,假设在银行里面保存,验证一个帐户。每个帐户都有帐户号码和金额。你能查询金额,存款或取款。我们能对此建模,抽象出一个基本的帐户类并且给与通用的变量和方法:
我们将此类标记为抽象的,这样的话,Account对象是不能够直接被创建出来的(继承的类只需要savings accounts or checking accounts)
accountNum和balance 变量持有帐户号码和当前的帐户金额。 而余下的那些方法则提供了基本的取钱,存钱和查询金额的功能。 T
我们能定义一个SavingsAccount,并使用extends关键字来继承得到这些变量和方法。
因为SavingsAccount是Account的子类,所以它将自动的包含Account里面所有的实例变量和方法。这可以使我们专注于SavingsAccount所特有的属性和方法(比如,如果帐户金额小于100,则无法取款)
类似的,我们再定义一个CheckingAccount类继承Account
这里定义了一个变量,来判断帐户持有者能否透支。(如果取款的时,取款金额超过了帐户现有金额,那么透支功能将起作用,判断此用户是否能透支)注意,在这里我们修改了继承的withdraw方法,这就是方法的覆盖,所以方法前面需要加上override关键字
目录
- 绑定概述
- 绑定和对象
- 绑定和方法
- 绑定序列
- 替换触发器
-绑定的概念
bind关键字将目标变量的值和一个范围表达式联系(bound expression)起来。范围表达式可以是基本类型,一个对象,方法的返回值或者一个表达式的返回值。
下面的章节将一个个的举例。
-绑定和对象
现实中,大部分情况下,你要使用数据绑定,来同步GUI和它的数据
(GUI是 《Building GUI Applications with JavaFX》的主题; 下面我们演示的是简单的非GUI例子)
我们从简单的开始:下面的脚本中,将变量x绑定到了变量y上,改变x的值,然后打印出y的值。由于变量被绑定了,y的值会自动的更新为新值。
var x = 0; def y = bind x; x = 1; println(y); // y now equals 1 x = 47; println(y); // y now equals 47
注意,我们是用def声明的变量y。这样的话,能够阻止直接修改y的值!(y的值允许以绑定的方式修改)在下面的绑定对象的例子中,你应该以相同的方式来绑定。
var myStreet = "1 Main Street"; var myCity = "Santa Clara"; var myState = "CA"; var myZip = "95050"; def address = bind Address { street: myStreet; city: myCity; state: myState; zip: myZip; }; println("address.street == {address.street}"); myStreet = "100 Maple Street"; println("address.street == {address.street}");
当你修改myStreet的值的时候,address对象里的street变量的值也会随之改变。
address.street == 1 Main Street address.street == 100 Maple Street
注意,myStreet值的改变将导致一个新的Address对象被创建,并且这个对象被赋予了address变量。如果想改变值,但是不要新创建一个新的Address对象,直接在实例变量上进行绑定。
def address = bind Address { street: bind myStreet; city: bind myCity; state: bind myState; zip: bind myZip; };
如果你已明确的对实例变量进行了绑定,那么你可以省略第一个bind(Address前面的那个bind)
def address = Address { street: bind myStreet; city: bind myCity; state: bind myState; zip: bind myZip; };
-绑定和方法
前面已经讨论过方法了,但是你还要学习一下bound functions 和non-bound functions之间的差别。
下面的方法,它创建并返回一个Point对象:
var scale = 1.0; bound function makePoint(xPos : Number, yPos : Number) : Point { Point { x: xPos * scale y: yPos * scale } } class Point { var x : Number; var y : Number; }
这就是所谓的bound function,因为它以bound关键字开头。
Note: bound关键字不是替代bind关键字的。在下面的例子里面,将会同时使用bound和bind.
接着,我们添加一些代码来调用这个方法并测试绑定:
var scale = 1.0; bound function makePoint(xPos : Number, yPos : Number) : Point { Point { x: xPos * scale y: yPos * scale } } class Point { var x : Number; var y : Number; } var myX = 3.0; var myY = 3.0; def pt = bind makePoint(myX, myY); println(pt.x); myX = 10.0; println(pt.x); scale = 2.0; println(pt.x);
输出:
3.0
10.0
20.0
我们来分析这段代码:
代码:
var myX = 3.0; var myY = 3.0; def pt = bind makePoint(myX, myY); println(pt.x);
初始化变量myX和myY为3.0。这些值将已参数的方式传给makePoint方法。makePoint方法前面的bind关键字,将新创建的Point对象pt绑定到了makePoint方法的返回值上。(
The bind keyword, placed just before the invocation of makePoint, binds the newly created Point object (pt) to the outcome of the makePoint function.)[这里字面意思是pt绑定到了makePoint的返回值上去了,我理解的是返回值绑定到pt上去。]
下一段代码:
myX = 10.0; println(pt.x);
修改myX的值为10.0然后打印pt.x。pt.x也将输出10.0
最后一段代码:
scale = 2.0; println(pt.x);
修改scale的值并打印出pt.x。现在pt.x的值是20.0,如果我们将方法前面的bound关键字去掉(就变成了non-bound function),输出将会是:
3.0 10.0 10.0
这是因为non-bound functions只有在它的参数发生改变的时候才会重新执行。而scale并不是方法的参数,所以改变scale的值不会对方法产生影响。
-绑定序列
你还可以在表达式上使用bind。要解释这一点,让我们先来定义两个序列并打印他们的值。
var seq1 = [1..10]; def seq2 = bind for (item in seq1) item*2; printSeqs(); function printSeqs() { println("First Sequence:"); for (i in seq1){println(i);} println("Second Sequence:"); for (i in seq2){println(i);} }
seq1有10个项(1到10).seq2也有10个项,并且和seq1的值相等,但是我们给每项都乘以了2,所以值将是seq1的两倍。
输出:
第一个序列:
1
2
3
4
5
6
7
8
9
10
第二个序列:
2
4
6
8
10
12
14
16
18
20
只要在for关键字前面加上bind关键字,我们就能将两个序列绑定了。
def seq2 = bind for (item in seq1) item*2;
现在的问题就是“如果seq1里面发生改变了,seq2里面的所有项或部分项会有影响吗?”我们可以在seq1的末尾插入一项(值为11)来测试一下。
var seq1 = [1..10]; def seq2 = bind for (item in seq1) item*2; insert 11 into seq1; printSeqs(); function printSeqs() { println("First Sequence:"); for (i in seq1){println(i);} println("Second Sequence:"); for (i in seq2){println(i);} }
输出:
第一列:
1
2
3
4
5
6
7
8
9
10
11
第二列:
2
4
6
8
10
12
14
16
18
20
22
输出显示了在seq1中插入11后,对seq2里的前面10项并没有产生影响,而是自动的加到了seq2的后面,并且值是22.
-替换触发器(replace trigger)
替换触发器是一段特殊的代码,它和变量关联,并且只要变量的值发生改变就会执行。下面的例子展示了基本的语法:定义了一个password变量并和一个替换触发器关联,当password改变的时候,触发器打印出password的新值。
var password = "foo" on replace oldValue { println("\nALERT! Password has changed!"); println("Old Value: {oldValue}"); println("New Value: {password}"); }; password = "bar";
输出:
ALERT! Password has changed!
Old Value:
New Value: foo
ALERT! Password has changed!
Old Value: foo
New Value: bar
这里触发器被触发了两次:第一次,当password被初始化为"foo"的时候,以及第二次当值变成"bar"时。
注意,oldValue变量持有触发器执行前变量的值。你能够任意命名此变量,我们使用oldValue只是因为它比较直观。
Lesson 9: Writing Your Own Classes
目录
- 例子:Customer
- 从其他类继承
-例子:Customer
在Writing Scripts章节,你学会了如何使用对象。但是,当时我们是让你去下载了.class文件,以使编译器知道怎么去创建Address和Customer对象。在下面的例子里面,我们重新来看代码,新增缺少的类定义,以保证所有的代码都能通过编译。
def customer = Customer { firstName: "John"; lastName: "Doe"; phoneNum: "(408) 555-1212" address: Address { street: "1 Main Street"; city: "Santa Clara"; state: "CA"; zip: "95050"; } } customer.printName(); customer.printPhoneNum(); customer.printAddress(); class Address { var street: String; var city: String; var state: String; var zip: String; } class Customer { var firstName: String; var lastName: String; var phoneNum: String; var address: Address; function printName() { println("Name: {firstName} {lastName}"); } function printPhoneNum(){ println("Phone: {phoneNum}"); } function printAddress(){ println("Street: {address.street}"); println("City: {address.city}"); println("State: {address.state}"); println("Zip: {address.zip}"); } }
如果你已经掌握了变量和方法,那么这段代码你应该很容易理解。Address类声明了street, city, state, and zip实例变量,且都是String类型。Customer也声明了一些实例变量还有一些方法来打印他们的值。因为这些变量和方法都是在类里面声明的,所以在你创建的任意的Address和Customer类的实例都能够访问到他们。
-从其他类继承
你还能创建一个类,并从其他类里面继承变量和方法。例如,假设在银行里面保存,验证一个帐户。每个帐户都有帐户号码和金额。你能查询金额,存款或取款。我们能对此建模,抽象出一个基本的帐户类并且给与通用的变量和方法:
abstract class Account { var accountNum: Integer; var balance: Number; function getBalance(): Number { return balance; } function deposit(amount: Number): Void { balance += amount; } function withdraw(amount: Number): Void { balance -= amount; } }
我们将此类标记为抽象的,这样的话,Account对象是不能够直接被创建出来的(继承的类只需要savings accounts or checking accounts)
accountNum和balance 变量持有帐户号码和当前的帐户金额。 而余下的那些方法则提供了基本的取钱,存钱和查询金额的功能。 T
我们能定义一个SavingsAccount,并使用extends关键字来继承得到这些变量和方法。
class SavingsAccount extends Account { var minBalance = 100.00; var penalty = 5.00; function checkMinBalance() : Void { if(balance < minBalance){ balance -= penalty; } } }
因为SavingsAccount是Account的子类,所以它将自动的包含Account里面所有的实例变量和方法。这可以使我们专注于SavingsAccount所特有的属性和方法(比如,如果帐户金额小于100,则无法取款)
类似的,我们再定义一个CheckingAccount类继承Account
class CheckingAccount extends Account { var hasOverDraftProtection: Boolean; override function withdraw(amount: Number) : Void { if(balance-amount<0 and hasOverDraftProtection){ // code to borrow money from an overdraft account would go here } else { balance -= amount; // may result in negative account balance! } } }
这里定义了一个变量,来判断帐户持有者能否透支。(如果取款的时,取款金额超过了帐户现有金额,那么透支功能将起作用,判断此用户是否能透支)注意,在这里我们修改了继承的withdraw方法,这就是方法的覆盖,所以方法前面需要加上override关键字
评论 共 0 条 请登录后发表评论