Classes
出自OpenFace
第二十章 类
第四部分 进级概念
本章以我们的类系统的基本特征的简明概要开始,以怎样有效的使用LZX的评论结尾。
本章解释了OpenLaszlo 应用中面向对象编程的基本概念,特别是<class>标签。
目录 |
概况
类是LZX编程的核心。根据你个人情况,你可以参阅几种OpenLaszlo文档以学习怎样在你的应用中有效的使用类。
为了找到在 OpenLaszlo应用中使用类的感觉,你可以先阅读类的介绍。那是开始学习的最佳资料,尤其是你从未学习过面向对象编程。
你在阅读的本章包含对Laszlo的类的更简明的说明和LZX相关的面向对象系统的诠释。特别的,本章假定你已掌握了指南中的概念。我们会忽略怎样创建和继承类以及怎样设计LZX支持的快速应用开发的探究。
第24章,类的继承为更多的开发者增加经验。它提供更先进的技术。
class语法摘要
在最简单的形式中,类可以作为宏用于,在复杂的结构中简化为一个单独的标签。下例定义了一个square类,并进行了两次实例化。
Example 20.1. Defining a new tag
<canvas height="20"> <class name="square" extends="view"/> <square width="20" height="20" bgcolor="red"/> <square x="30" width="20" height="20" bgcolor="red"/> </canvas>
该例等价于下例,但更简短更易理解和掌握。
Example 20. 没有class标签
<canvas height="20"> <view width="20" height="20" bgcolor="red"/> <view x="30" width="20" height="20" bgcolor="red"/> </canvas>
除此之外,第一个例子中定义的类可以通过使用<library> and <include>标签移动到一个单独的文件中。
Example 20.3 在library定义标签
<canvas height="20"> <include href="square.lzx"/> <square width="20" height="20" bgcolor="red"/> <square x="30" width="20" height="20" bgcolor="red"/> </canvas>
<library> <class name="square" /> </library>
属性
类的属性对每个实例都是默认的属性。实例可以通过提供自己的属性重写这些属性。
Example 20.4 属性复制
<canvas height="20"> <include href="square.lzx"/> <square /> <square x="30" bgcolor="green"/> </canvas>
属性
若一个类的定义中包含子节点,则这些子节点被类的实例继承。
Example 20.5
<canvas height="30">
<class name="myframe" >
<view x="2" y="2" width="16" height="16" bgcolor="blue"/>
</class>
<myframe bgcolor="red"/>
<myframe x="30" bgcolor="red"/>
</canvas>
Example 20.6
<canvas height="200" width="200">
<class name="myframe" extends="view">
<view x="5" y="5" width="${parent.width-10}" height="${parent.height-10}" bgcolor="blue"/>
</class>
<myframe width="40" height="40" bgcolor="red"/>
</canvas>
这里的extends属性不是必须的。默认的基类是LzView类。
创建一个myframe实例
函数
类中定义的方法对类的实例都是可用的,并且重写的超类方法可以通过super关键字调用。
与很多面向对象系统不同,Laszlo允许在类的实例中重写类的方法。
Text 类
The <text> and <inputtext>标签在类的构建中它们持有的文本内容是唯一的。
Example 20.7. 创建text类
<canvas height="50"> <simplelayout/> <inputtext>plain text</inputtext> <text>text</text> </canvas>
<inputtext>标签可能包含text字符.
文本内容作为类的text属性是可用的.
Example 20.8. 继承text类
<canvas height="50"> <simplelayout/> <class name="mytext" extends="text"/> <class name="myinputtext" extends="inputtext"/> <myinputtext>plain text</myinputtext> <mytext> text</mytext> </canvas>
布局
类的内部结构对它的分级的子节点通常是不可见的。默认情况下,出现在类内部的实例使子节点成为类的顶层实例。这对容器类通常是不合理的。
Example 20.9. 类里缺省布局
<canvas height="50">
<class name="myframe" extends="view">
<view x="5" y="5" width="${parent.width-10}" height="${parent.height-10}" bgcolor="#FFFFCC" />
</class>
<myframe width="220" height="20" bgcolor="red">
<text>This is some text</text>
</myframe>
</canvas>
已知错误: 属性defaultplacement的值必须是双引用的。("")
Example 20.10.
<canvas height="50">
<class name="myframe" extends="view">
<attribute name="defaultplacement" value="'iv'"/>
<view x="5" y="5" width="${parent.width-10}" name='iv' height="${parent.height-10}" bgcolor="#FFFFCC"/>
</class>
<myframe width="220" height="50" bgcolor="red">
<text>This is some text</text>
</myframe>
</canvas>
类里定义约束
约束使一个属性值与其他属性的值关联的一般机制,如第19章所述。
在类的定义时使用约束要谨慎。这依赖于你用于指定约束的语法,你可能会遇到以下问题:
由类的所有实例共享的单一的实体,或者
类的每个实例的唯一实体
创建共享对象
创建共享对象
类的定义中可以使用以下形式: value="[]" value="new Array()" value="{}" value="new Object()"
你会得到一个由所有实例共享的单一数组或对象
为每个实例创建唯一的对象
在类的定义中,可以使用以下形式: value="${[]}" value="${new Array()}" value="${{}}" value="${new Object()}"
每个实例都会获取自己的数组和对象。
注意${}等价于 $always{}, 但由于每部的表达式没有依赖,它也 等价于$once{}。 因此也许使用$once{}语法更好。这也可以提高可读性。
对名称进行引用
不管怎样实例类,你都可以给view命名,并象下面那样访问它:
Example 20.11. 对名称进行处理
<canvas>
<script>
var foo = new LzView(canvas, {width:50,height:50,x:50,y:100,bgcolor:0,name:"myview"});
</script>
<text>Make window red
<handler name="oninit">
var nameOfView = "myview";
canvas[nameOfView].setAttribute('bgcolor', 0xff0000);
</handler>
</text>
</canvas>
原型语言
LZX是基于原型的语言:任何属性都可以附属于类的 定义或类的实例。这在有很多一次性行为对象的UI程序中是很方便的。这对原型和程序开发的扩展新颖的分解创建可能性也很方便。
下面的两个XML 文件完全是LZX程序。每个都定义了名为myview的视图,它们都包含一个名为f的方法。在每个应用中通过返回100评价方法f。
Example 20.12. 函数
<canvas> <view id="myview"> <method name="f">return 100;</method> </view> </canvas>
Example 20.13 类里的函数
<canvas> <class name="myclass"> <method name="f">return 100;</method> </view> <myclass id="myview"/> </canvas>
实例开发
以上两个程序从提供的开发策略的角度而言是等价的。
全局变量
一次实例技术是使用全局变量。通常开发和调试存储全局变量状态的程序比使用局部变量,session,用户对象的程序更容易。这样可以避免通过API调用的环环相扣的情况,而且可以容易的找到并操作状态。
最后你可以将全局变量转换成状态对象的成员,这种转变是相对简单的,特别是你已经用这种知识写了程序。这种技术比其他所有的程序转换时维持状态和写额外的访问更廉价。这对于你打算转换程序的原则是特别的情况。你可以优化要转化的程序的顺序。在一次实例开发的全局变量中,整个程序是一个实例。基于原型的程序支持不依赖全局变量的其他途径。 用基于原型的程序,你可以增加功能性并和对象的实例进行交互,在另一个同名实例被调用时把它它的成员转变成类。这样可以避免程序的 缺陷,不成熟性,过早产生无显著特点的行为的地方,必须在框架层重写,很难给出调试的原因和花费,而不是在具体的实例层。从两个例子比一个更容易归纳出特点。
在没有原型的语言中,你可以通过执行"singleton"类为实例驱动开发提供这种策略。原型简便的取代了开发中必须的中间部分,减少行数等。这在用户实例存在很多一次性可视对象的程序时特别有用。使用单独的类会明显的增加程序的规模,但你想自由快速的把它们加到类中。一门语言中原型也支持类。
一次实例开发类似于测试驱动开发,但有区别。在测试驱动开发中,你增加功能性的测试细节来解决增长的测试问题。在一次实例开发中,你增加功能性的实例细节给实例,从而总结。两者都是先执行具体例子,然后由它们进行归纳。
实例替代原则
在LZX中,类是用户定义的XML标签,它和非XML语言中类的定义是等价的。
理解LZX类定义的时候,你可以发现以下有用的原则:
实例置换原则:类的实例可以由实例的定义取代, 而不改变程序。
文章开始的两个程序说明了实例置换原则。
实例置换原则可以应用于语义学层面,或者语法级。对语义学,它意思是一个成员可以附属于 类或它的实例。对语法层,意味着定义类成员和实例。
LZX和其它语言的比较
很多基于原型的语言不遵从实例置换原则,或许因为它们没有类,或许类和实例的定义不是平行的。JavaScript 1.0版本也是基于原型的语言,但是缺少类作为实体,并且缺少分级语法,Java, C++, 和 LZX使用定义类成员。JavaScript 2.0,JScript.NET, 和Python 有类定义语法,但不使用想通的语法定义实例成员。例如:对比下面的两个于lzx程序平行的Python程序:
myobject = object() myobject.f = lambda f: 100
class MyClass(object): def f(): return 100 myobject = MyClass()
这种实例置换原则的版本使得类看起来象函数或宏。类。函数。宏定义都是可重用的抽象程序结构的机制。
有些语言隐藏了这一点,因为它们缺少细节和普通例子的机制.例如实例置换原则只对有原型和类的语言有意义;在诸如缺少匿名函数表现中间级的C++或Java等语言中顺序的陈述函数定义的出处是很难的。

