目录
IRIS 对象类简介
InterSystems IRIS
通过以下对象类提供对象技术:%Library.RegisteredObject
、%Library.Persistent
和 %Library.SerialObject
。
下图显示了这些类之间的继承关系,以及它们的一些参数和方法。类名称%Library包可以缩写,(例如)%Persistent
是 %Library.Persistent
的缩写。此处,所有大写字母的项都是参数,以百分号开头的项是方法。
在典型的基于类的应用程序中,基于这些类(以及专用系统子类)定义类。所有对象都直接或间接地从这些类之一继承,并且每个对象都是以下类型之一:
- 已注册的对象是
%RegisteredObject
的实例或子类。您可以创建这些对象,但不能保存它们。另外两个类继承自%RegisteredObject
,因此包括该类的所有参数、方法等。 - 持久性对象是
%Persistent
的实例或子类。您可以创建、保存、打开和删除这些对象。
持久性类会自动投影到可通过 Caché SQL 访问的表中。 - 序列化对象是
%SerialObject
对象的实例或子类。序列化类旨在用作另一个对象的属性。您可以创建和删除这些对象,但不能保存它们或独立于包含它们的对象打开它们。
当包含在持久性对象中时,这些对象具有到 SQL 的自动投影
。
对象类的基本功能
使用对象类,您可以执行以下任务,其中包括:
- 您可以创建一个对象(类的实例)。为此,请使用该类的
%New()
方法,该方法继承自%RegisteredObject
。例如:
set myobj=##class(Sample.Person).%New()
- 您可以使用属性。
您可以在任何类中定义属性,但它们仅在对象类中有用,因为只有这些类使您能够创建实例。
任何属性都包含单个文本值、对象(可能是集合对象)或多维数组(罕见)。下面的示例演示对象值属性的定义:
Property Home As Sample.Address;
- 如果类或其超类定义了实例方法,则可以调用该类的实例的方法。例如:
Method PrintPerson()
{
Write !, "Name: ", ..Name
Quit
}
如果 myobj 是定义此方法的类的实例,则可以按如下方式调用此方法:
Do myobj.PrintPerson()
-
您可以验证属性值是否符合属性定义中给出的规则。
- 所有对象都继承实例方法
%NormalizeObject()
,该方法规范化对象的所有属性值。许多数据类型允许同一值的不同表示形式。规范化将值转换为其规范或规范化形式。%NormalizeObject() 根据此操作是否成功,返回 true 或 false。 - 所有对象都继承实例方法
%ValidateObject()
,该方法根据属性值是否符合属性定义返回 true 或 false。 - 所有持久性对象都继承实例方法
%Save()
。使用%Save()
实例方法时,系统首先自动调用%ValidateObject()
。
相反,当您在例程级别工作并且不使用类时,您的代码必须包含逻辑来检查类型和其他输入要求。
- 所有对象都继承实例方法
-
您可以定义
回调方法
,以便在创建、修改对象等时添加其他自定义行为。
例如,若要创建类的实例,请调用该类的%New()
方法。如果该类定义了%OnNew()
方法(回调方法),则Caché
也会自动调用该方法。下面显示了一个简单的示例:
Method %OnNew() As %Status
{
Write "hi there"
Quit $$$OK
}
在实际情况下,此回调可能会执行一些所需的初始化。它还可以通过写入文件或全局变量来执行日志记录。
OREFs
对象类的 %New()
方法创建一个内存中的内部结构来包含对象的数据,并返回指向该结构的 OREF
(对象引用)。OREF
是 Caché ObjectScript
中的一种特殊值。您应该记住以下几点:
- 在终端中,当您显示
OREF
时,您会看到一个由数字组成的字符串,后跟一个@
符号,后跟类的名称。例如:
SAMPLES>set myobj=##class(Sample.Person).%New()
SAMPLES>w myobj
3@Sample.Person
- 如果不使用
OREF
,则Caché
会在需要 OREF 的情况下返回错误:<INVALID OREF>
,能够识别此错误会很有帮助。这意味着该变量不是OREF
,但应该是OREF
。
SAMPLES>set myobj.Name="Fred Parker"
SET myobj.Name="Fred Parker"
^
<INVALID OREF>
- 创建
OREF
的方法只有一种:使用返回OREF
的方法。返回OREF
的方法在对象类或其子类中定义。
以下内容不会创建OREF
,而是创建看起来像OREF
的字符串:
SAMPLES>set testthis="4@Sample.Person"
- 您可以通过编程方式确定变量是否包含
OREF
。如果变量包含OREF
,则函数$IsObject
返回 1 (true);否则,它将返回 0(假)。
流接口类
Caché
分配固定的空间量来保存字符串操作的结果。如果字符串表达式超过分配的空间量,则会产生<MAXSTRING>
错误。除非启用长字符串
,否则此限制为 32 KB
,并且任何字符串属性都不能大于大约 32 KB。(其他任何属性也不能超过此限制,但其他限制会在长字符串限制应用之前生效)
如果需要传递长字符串值,或者需要属性来包含长字符串值,请使用流(stream
)。流
是一个对象,可以包含其大小大于字符串大小限制的单个值。(在内部,Caché
创建并使用临时全局变量以避免内存限制)
您可以将流字段与 Caché SQL 一起使用,但有一些限制。
stream 类
主要的 Caché
流类使用由 %Stream.Object
类定义的公共流接口。通常使用流作为其他对象的属性,并保存这些对象。流数据可以存储在外部文件或 Caché 全局文件中,具体取决于您选择的类:
%Stream.FileCharacter
和%Stream.FileBinary
类用于写入外部文件的流
。
(二进制流包含与%Binary
类型相同类型的数据,并且可以保存大型二进制对象(如图片)。字符流包含与%String
类型相同类型的数据,用于存储大量文本。%Stream.GlobalCharacter
和%Stream.GlobalBinary
类用于存储在全局变量中的流
。
若要使用流对象,请使用其方法。例如,使用这些类的Write()
方法将数据添加到流中,并使用Read()
从流中读取数据。流接口包括其他方法,如Rewind()
和MoveTo()
。
例如,下面的代码创建一个全局字符流,并将一些数据写入其中:
Set mystream=##class(%Stream.GlobalCharacter).%New()
Do mystream.Write("here is some text to store in the stream ")
Do mystream.Write("here is some more text")
Write "this stream has this many characters: ",mystream.Size,!
Write "this stream has the following contents: ",!
Write mystream.Read()
集合类
当您需要一个容器来存储相关值集时,可以使用$LIST
格式列表和多维数组,如本书前面所述。
如果您更喜欢使用类,Caché
提供了列表类和数组类;这些称为集合
。
用作独立对象的列表和数组类
- 若要创建列表对象,可以使用以下类:
%Library.ListOfDataTypes
— 定义文本值的列表。
%Library.ListOfObjects
— 定义对象列表(持久性或序列化)。
若要操作列表对象,请使用其方法。例如:
Set Colors=##class(%Library.ListOfDataTypes).%New()
Do Colors.Insert("Red")
Do Colors.Insert("Green")
Do Colors.Insert("Blue")
Write "Number of items in this list: ", Colors.Count()
Write !, "Second item in the list: ", Colors.GetAt(2)
- 同样,若要创建数组对象,可以使用以下类:
%Library.ArrayOfDataTypes
— 定义文本值的数组。每个数组项都有一个键和一个值。
%Library.ArrayOfObjects
— 定义对象数组(持久性或序列化)。每个数组项都有一个键和一个对象值。
若要操作数组对象,请使用其方法。例如:
Set ItemArray=##class(%Library.ArrayOfDataTypes).%New()
Do ItemArray.SetAt("example item","alpha")
Do ItemArray.SetAt("another item","beta")
Do ItemArray.SetAt("yet another item","gamma")
Do ItemArray.SetAt("still another item","omega")
Write "Number of items in this array: ", ItemArray.Count()
Write !, "Item that has the key gamma: ", ItemArray.GetAt("gamma")
列表和数组作为属性
还可以将属性定义为列表或数组。
- 若要将属性定义为列表,请使用以下格式:
Property MyProperty As list of Classname;
如果 Classname
是数据类型类,则Caché
使用 %Collection.ListOfDT
提供的接口。如果 Classname
是一个对象类,则它使用 %Collection.ListOfObj
提供的接口。
- 若要将属性定义为数组,请使用以下格式:
Property MyProperty As Array of Classname;
如果 Classname
是一个数据类型类,则 Caché
使用 %Collection.ArrayOfDT
提供的接口。如果 Classname
是一个对象类,则它使用%Collection.ArrayOfObj
提供的接口。
实用的 Caché ObjectScript 方法
Caché ObjectScript
提供了以下函数,用于对象类:
$CLASSMETHOD
$CLASSMETHOD
使您能够运行类方法,以类名和方法名的形式给出。例如:
SAMPLES>set class="Sample.Person"
SAMPLES>set obj=$CLASSMETHOD(class,"%OpenId",1)
SAMPLES>w obj.Name
Van De Griek,Charlotte M.
当您需要编写执行类方法的泛型代码
,但类名(甚至方法名)事先不知道时,此函数很有用。例如:
//read name of class from imported document
Set class=$list(headerElement,1)
// create header object
Set headerObj=$classmethod(class,"%New")
$METHOD
$METHOD
使您能够在给定实例和方法名称的情况下运行实例方法。例如:
SAMPLES>set obj=##class(Sample.Person).%OpenId(1)
SAMPLES>do $METHOD(obj,"PrintPerson")
Name: Van De Griek,Charlotte M.
$PROPERTY
$PROPERTY
获取或设置给定实例的给定属性的值。例如:
SAMPLES>set obj=##class(Sample.Person).%OpenId(2)
SAMPLES>write $property(obj,"Name")
Edison,Patrick J.
$PARAMETER
$PARAMETER获取给定类参数的值(给定一个实例)。例如:
SAMPLES>set obj=##class(Sample.Person).%OpenId(2)
SAMPLES>write $parameter(obj,"EXTENTQUERYSPEC")
Name,SSN,Home.City,Home.State
$CLASSNAME
$CLASSNAME
返回给定实例的类名。例如:
SAMPLES>set obj=##class(Sample.Person).%OpenId(1)
SAMPLES>write $CLASSNAME(obj)
Sample.Person
如果没有参数,此函数返回当前上下文的类名。这在实例方法中非常有用。