第六章 Caché 使用注册对象

文章目录

  • 第六章 使用注册对象
  • 对象类介绍
  • OREF基础知识
    • 无效的OREF错误
    • 测试一个OREF
    • OREFs, Scope, and Memory
    • 删除OREF
    • OREFs、SET命令和系统功能
  • 创建新对象
  • Viewing Object Contents
  • "."点语法简介
    • 层叠点语法
    • null的点语法
  • 验证对象
  • 确定对象类型
  • %Extends()
  • %IsA()
  • %ClassName()和最特定的类型类 (MSTC)
  • 克隆对象
  • 引用实例的属性
  • 调用实例的方法
  • 从实例获取类名
  • $this变量(当前实例)
  • i% PropertyName(实例变量)

第六章 使用注册对象

注意: %RegisteredObject 是抽象类 不能实例化

对象类介绍

对象类是继承自%RegisteredObject的任何类。使用对象类,可以做以下事情:

  • 创建类的实例。这些实例称为对象。
  • 设置对象的属性。
  • 调用那些对象的方法(实例方法)。
    只有使用对象类才能执行这些任务。
    类%Persistent和%SerialObject是%RegisteredObject的子类。

OREF基础知识

当创建一个对象时,Caché会创建一个内存中的结构,该结构保存关于该对象的信息,同时还创建一个OREF(对象引用),它是指向该结构的指针。
对象类提供了几个创建OREF的方法。在处理任何对象类时,都要广泛地使用OREF。在指定对象的属性值、访问对象的属性值和调用对象的实例方法时使用它们。考虑下面的例子:

SAMPLES>set person=##class(Sample.Person).%New()
 
SAMPLES>set person.Name="Carter,Jacob N."
 
SAMPLES>do person.PrintPerson()
 
Name: Carter,Jacob N.

在第一步中,我们调用样本的%New()方法。Person类,它创建一个对象并返回一个指向该对象的OREF。我们设变量person等于这个OREF。在下一步中,我们将设置对象的Name属性。在第三步中,我们调用对象的PrintPerson()实例方法。(注意Name属性和PrintPerson()方法都是示例—它们在示例中定义。

OREF是瞬态的;该值仅在对象位于内存中时存在,并且不能保证在不同的调用中是常量。

无效的OREF错误

在简单表达式中,如果试图设置属性、访问属性或调用非OREF变量的实例方法,则会收到一个错误。例如:

SAMPLES>write p2.PrintPerson()
 
WRITE p2.PrintPerson()
^

SAMPLES>set p2.Name="Dixby,Jase"
 
SET p2.Name="Dixby,Jase"
^

/// d ##class(PHA.OP.MOB.Test).TestingOREF()
ClassMethod TestingOREF()
{
	s p2=""
    w p2.PrintPerson()
}

测试一个OREF

Caché 提供了一个函数$ISOBJECT,可以使用它来测试给定的变量是否包含OREF。如果变量包含OREF,则此函数返回1,否则返回0。如果给定的变量不包含OREF,那么在尝试设置属性、访问属性或调用变量的实例方法之前,最好先使用这个函数。

/// d ##class(PHA.OP.MOB.Test).TestingOREF()
ClassMethod TestingOREF()
{
	s p2=""
	i $isobject(p2)
	.w p2.PrintPerson()
	e  d
	.w "不是OERF"
}

OREFs, Scope, and Memory

任何给定的OREF都是指向其他OREF也可能指向的内存对象的指针。也就是说,OREF(它是一个变量)与内存中的对象不同(尽管在实践中,术语OREF和对象经常互换使用)。

注意以下几点:

  • OREF仅在特定名称空间内有效;因此,如果存在现有的OREF和当前的名称空间更改,则先前名称空间中的任何OREF都不再有效。 如果尝试从其他名称空间使用oref,可能不会立即出现错误,但是结果不能被认为是有效的或可用的,并可能导致当前名称空间中出现灾难性的结果。
  • Caché自动管理内存中的结构,如下所示。对于每个内存中的对象,Caché维护一个引用计数——该对象的引用数量。无论何时设置变量或对象属性来引用对象,其引用计数都会自动递增。当一个变量停止引用一个对象(如果它超出范围,被杀死,或被设置为一个新值),该对象的引用计数将递减。当该计数变为0时,对象将自动销毁(从内存中删除),并调用其%OnClose()方法(如果存在)。

例如:

Method Test()
{
    Set person = ##class(Sample.Person).%OpenId(1)

    Set person = ##class(Sample.Person).%OpenId(2)
}

此方法创建Sample的一个实例。并将对它的引用放入变量Person中。然后它创建另一个Sample实例。将Person的值替换为对它的引用。此时,第一个对象不再被引用并被销毁。在方法结束时,person超出范围,第二个对象被销毁。

删除OREF

如果需要删除OREF,请使用KILL命令:

kill OREF
  • OREF 是一个包含OREF的变量。此命令删除变量。如果没有对该对象的进一步引用,该命令还将该对象从内存中删除,如前所述。
/// d ##class(PHA.OP.MOB.Test).KillOREF()
ClassMethod KillOREF()
{
	
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New()
	s LocalInstance1 = ##class(PHA.OP.MOB.TestTwo).%New()
	s LocalInstance.date=+$h
	s LocalInstance1.date=+$h
	w "LocalInstance: "_LocalInstance.date,!
	k LocalInstance
	w "LocalInstance1: "_LocalInstance1.date,!
	;s LocalInstance.date=+$h //K掉后 就写不出来了
}

OREFs、SET命令和系统功能

对于某些系统函数(例如 P i e c e 、 Piece、 PieceExtract和$List),Caché支持一种可用于修改现有值的替代语法。该语法将函数与SET命令组合如下:

/// d ##class(PHA.OP.MOB.Test).KillOREF()
ClassMethod KillOREF1() [ Language = basic ]
{
	
	SET function_expression = value
}
  • function_expression 对系统函数的调用,带有参数,值就是值。例如,下面的语句将colorlist字符串的第一部分设置为“Magenta”:
SET $PIECE(colorlist,",",1)="Magenta"

不支持以这种方式修改oref或它们的属性。

创建新对象

要创建给定对象类的新实例,请使用该类的类方法%new()。该方法创建一个对象并返回一个OREF。以下是一个例子:

 Set person = ##class(MyApp.Person).%New()

%New()方法接受一个参数,默认情况下忽略该参数。如果存在,则将此参数传递给已定义的类的%OnNew()回调方法。如果定义了%OnNew(),它可以使用参数以某种方式初始化新创建的对象。

Class PHA.OP.MOB.TestTwo Extends PHA.OP.MOB.Test
{

Property date As %Date;

Property value As %Date;

Method %OnNew(initvalue As %String) As %Status [ Private, ServerOnly = 1 ]
{
	s ..value=initvalue
    s ..date=$zd(+$h,3)
    w ..date,!
    w ..value,!
    Quit $$$OK
}
}

%Status 返回值有2种

  • $$$ISOK(status:%Status)如果状态码状态不代表错误条件,则返回true(1)。

  • $$$ISERR(status:%Status)如果状态代码状态表示错误条件,则返回true(1)。

/// d ##class(PHA.OP.MOB.Test).TestOnNew()
ClassMethod TestOnNew()
{
	
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	s LocalInstance.date=+$h
	s value=LocalInstance.value
	w LocalInstance.date,!
	w value,!
}

如果有影响如何创建给定类的新对象的复杂需求,则可以提供用于创建该类实例的替代方法。这样的方法将调用%New(),然后根据需要初始化对象的属性。这种方法有时称为工厂方法。

Viewing Object Contents

w 命令为OREF写入以下形式的输出:

n@Classname
  • Classname 类的名称
  • n 是一个整数,表示该类在内存中的一个特定实例。
    例如
SAMPLES>write p
[email protected]

如果将ZWRITE命令与OREF一起使用,那么cache将显示有关关联对象的更多信息。

DHC-APP>d ##class(PHA.OP.MOB.Test).TestOnNew()
2020-02-08
测试
 
 b
 ^
zTestOnNew+2^PHA.OP.MOB.Test.1
DHC-APP 2d1>w LocalInstance
[email protected]
DHC-APP 2d1>zw LocalInstance
LocalInstance=[[email protected]]
+----------------- general information ---------------
|      oref value: 1
|      class name: PHA.OP.MOB.TestTwo
| reference count: 2
+----------------- attribute values ------------------
|               date = "2020-02-08"
|              value = "测试"
+-----------------------------------------------------
 
DHC-APP 2d1>
 
  

注意,该信息显示了类名、OID、引用计数和对象属性的当前值(在内存中)。在swizzled引用一节中,名称以i%开头的项是实例变量,本章稍后将对此进行讨论。(以r%开头的项目仅供内部使用。)

SAMPLES>zwrite p
p=[[email protected]]
+----------------- general information ---------------
|      oref value: 1
|      class name: Sample.Person
|           %%OID: $lb("3","Sample.Person")
| reference count: 2
+----------------- attribute values ------------------
|       %Concurrency = 1  
|                DOB = 33589
|               Name = "Clay,George O."
|                SSN = "480-57-8360"
+----------------- swizzled references ---------------
|   i%FavoriteColors = ""  
|   r%FavoriteColors = ""  
|             i%Home = $lb("5845 Washington Blvd","St Louis","NM",55683)  
|             r%Home = ""  
|           i%Office = $lb("3413 Elm Place","Pueblo","WI",98532)  
|           r%Office = ""  
|           i%Spouse = ""
|           r%Spouse = ""
+-----------------------------------------------------
 
  

"."点语法简介

使用OREF,可以使用"."点语法来引用关联对象的属性和方法。本节介绍点语法,后面的部分也将讨论点语法,以及引用对象的属性和方法的其他方法。

点语法的一般形式如下:

oref.membername

例如,要指定对象的属性值,可以使用如下语句:

 Set oref.PropertyName = value
  • oref OREF对象
  • PropertyName 要设置的属性的名称,而值是计算为所需值的Caché ObjectScript表达式。这个可以是常数,也可以是更复杂的表达式。

我们可以使用相同的语法来调用对象的方法(实例方法)。从类的特定实例调用实例方法,并通常执行与该实例相关的一些操作。在下面的例子中,我们调用对象的PrintPerson()方法:

 set person=##class(Sample.Person).%New() 
 set person.Name="Carter,Jacob N." 
 do person.PrintPerson()

如果方法返回一个值,可以使用SET命令将返回的值赋给一个变量:

SET myvar=oref.MethodName()

如果方法没有返回值(或者对返回值不感兴趣),则使用DO或JOB:

Do oref.MethodName()

如果方法接受参数,请在括号内指定它们。

 Set value = oref.methodName(arglist)

层叠点语法

根据类定义,属性可以是对象值的,这意味着它的类型是对象类。在这种情况下,可以使用oref链来引用属性的属性(或属性的方法)。这就是层叠点语法。例如,下面的语法引用Person对象的HomeAddress属性的Street属性:

set person.HomeAddress.Street="15 Mulberry Street"
/// d ##class(PHA.OP.MOB.Test).TestCascad()
ClassMethod TestCascad()
{
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	s age=LocalInstance.address.age
}

Class PHA.OP.MOB.TestTwo Extends PHA.OP.MOB.Test
{

Property date As %Date;

Property value As %Date;

Property address As PHA.OP.MOB.TestThree;
}

Class PHA.OP.MOB.TestThree Extends %RegisteredObject
{

Property age;
}

在本例中,person变量是OREF,表达式是person。家庭住址也是一个OREF。

通常在引用类成员时,有时使用以下非正式引用:PackageName.ClassName.Member, 例如, the Accounting.Invoice.LineItem property。这种形式永远不会出现在代码中。

null的点语法

当使用OREF链来引用属性或方法时,如果中间属性不是有效的OREF,Caché会在某些情况下抛出错误,但不是所有情况都是如此。

x.y.z
  • x 是一个有效的OREF
  • y 是x的一个对象值属性的名称,
  • z 是该属性的一个属性或方法。

下表列出了y不持有有效OREF时可能出现的情况;这些场景取决于属性y是否基于序列化对象

场景 属性y不是序列化对象 属性y是序列化对象
write x.y.z Writes a null value w 属性z的初始表达式
set x.y.z=“some value” error 属性已设置。
do x.y.z() error 方法被执行。

验证对象

RegisteredObject类提供了验证实例属性的方法。一个对象是有效的,如果所有下列为真:

  • 所有 required 属性都有值。(要使属性成为必需的,可以使用required关键字。
  • 每个属性的值(如果不是null)对于关联的属性定义是有效的。
    例如,如果属性类型为%Boolean,则值“abc”无效,但值0和1有效。
  • 每个文字属性的值(如果不是null)遵循属性定义定义的所有约束。术语约束指的是对属性值应用约束的任何属性关键字。例如,MAXLEN、MAXVAL、MINVAL、VALUELIST和PATTERN都是约束;
    例如,对于类型%String的属性,MAXLEN的默认值,这将限制该属性的长度不超过50个字符。
  • (对于对象值属性)对象的所有属性都遵循上述规则。
  • (对于持久对象)该对象不违反任何SQL约束,例如给定字段上的唯一性约束。

要确定给定对象是否有效,请调用其%ValidateObject()方法。如果此方法返回1,则该对象是有效的。如果返回错误状态,则该对象无效。以下是一个例子:

  #Include %occStatus
    set person=##class(Sample.Person).%New()
    set person.DOB="December 12 1990"
    set status=person.%ValidateObject()
    write !, "First try"
    if $$$ISERR(status) {
        do $system.OBJ.DisplayError(status)
    } else {
        write !, "Object is valid"
    }

    set person.Name="Ellsworth,Myra Q."
    set person.SSN="000-00-0000"
    set person.DOB=$zdateh("December 12 1990",5)
    set status=person.%ValidateObject()
    write !!, "Second try"
    if $$$ISERR(status) {
        do $system.OBJ.DisplayError(status)
    } else {
        write !, "Object is valid"
    }

运行这个例子,你会看到以下输出:

First try
ERROR #7207: Datatype value 'December 12 1990' is not a valid number
  > ERROR #5802: Datatype validation failed on property 'Sample.Person:DOB', with value equal to "December 12 1990"
ERROR #5659: Property 'Sample.Person::Name([email protected],ID=)' required
ERROR #5659: Property 'Sample.Person::SSN([email protected],ID=)' required
ERROR #7209: Datatype value '' does not match PATTERN '3N1"-"2N1"-"4N'
  > ERROR #5802: Datatype validation failed on property 'Sample.Person:SSN', with value equal to ""
 
Second try
Object is valid

注意,%ValidateObject()依次调用每个属性的验证逻辑;在保存对象时,Caché 首先自动调用%ValidateObject()方法。如果对象无效,缓存将不保存它。

/// d ##class(PHA.OP.MOB.Test).TestValidatingbjects()
ClassMethod TestValidatingbjects()
{
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	
	set status=LocalInstance.%ValidateObject()
	  write !, "First try"
    if $$$ISERR(status) {
        do $system.OBJ.DisplayError(status)
    } else {
        write !, "Object is valid"
    }
}

DHC-APP>d ##class(PHA.OP.MOB.Test).TestValidatingbjects()
2020-02-08
测试
 
First try
错误 #7207: 数据类型值'2020-02-08'不是有效的数字
  > 错误 #5802: 属性'PHA.OP.MOB.TestTwo:date'上的数据类型验证失败,值等于"2020-02                 -08"
错误 #7207: 数据类型值'测试'不是有效的数字
  > 错误 #5802: 属性'PHA.OP.MOB.TestTwo:value'上的数据类型验证失败,值等于"测试"
DHC-APP>

确定对象类型

给定一个对象,%RegisteredObject类提供确定其继承的方法。本节将讨论它们。

%Extends()

要检查对象是否继承自特定的父类,请调用其%Extends()方法,并将该超类的名称作为参数传递。如果此方法返回1,则实例将从该类继承。如果返回0,则实例不会从该类继承。例如:

SAMPLES>set person=##class(Sample.Person).%New()
 
SAMPLES>w person.%Extends("%RegisteredObject")
1
SAMPLES>w person.%Extends("Sample.Person")
1
SAMPLES>w person.%Extends("Sample.Employee")
0
/// d ##class(PHA.OP.MOB.Test).IsExtend()
ClassMethod IsExtend()
{
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	w LocalInstance.%Extends("%RegisteredObject"),!
	w LocalInstance.%Extends("PHA.OP.MOB.Test"),!
	w LocalInstance.%Extends("PHA.OP.MOB.Android"),!
}

DHC-APP>d ##class(PHA.OP.MOB.Test).IsExtend()
2020-02-08
测试
1
1
0
 
DHC-APP>

%IsA()

要检查一个对象是否有一个特定的类作为它的主父类,请调用它的%IsA()方法,并将该父类的名称作为参数传递。

/// d ##class(PHA.OP.MOB.Test).IsA()
ClassMethod IsA()
{
	s LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	w LocalInstance.%IsA("%RegisteredObject"),!
	w LocalInstance.%IsA("PHA.OP.MOB.Test"),!
	w LocalInstance.%IsA("PHA.OP.MOB.Android"),!
}

DHC-APP>d ##class(PHA.OP.MOB.Test).IsA()
2020-02-08
测试
1
1
0
 
DHC-APP>

%ClassName()和最特定的类型类 (MSTC)

尽管一个对象可能是多个类的实例,但它总是有一个最特定的类型类(MSTC)。当一个对象是该类的一个实例而不是该类的任何子类的实例时,一个类被称为对象的最特定类型。

例如,GradStudent类继承自Student类,而Student类又继承自Person类,例如,命令创建的实例:

 set MyInstance1 = ##class(MyPackage.Student).%New()
 set MyInstance2 = ##class(MyPackage.GradStudent).%New()

MyInstance1的MSTC是Student,因为它是Person和Student的实例,而不是GradStudent的实例。MyInstance2的MSTC是GradStudent,因为它是GradStudent、Student和Person的实例。

以下规则也适用于对象的MSTC:

  • 对象的MSTC完全基于主继承。
  • 非实例化类永远不能是对象的MSTC。如果对象类是抽象的,则它是不可实例化的。
    要确定对象的MSTC,请使用%ClassName()方法,该方法继承自%RegisteredObject
classmethod %ClassName(fullname As %Boolean) as %String
  • fullname 是一个布尔参数,其中1指定方法返回一个包名和类名,0(默认值)指定方法只返回类名。

例如

 write myinstance.%ClassName(1)

(类似地,可以使用%PackageName()来获取包的名称。)

/// d ##class(PHA.OP.MOB.Test).GetClassName()
ClassMethod GetClassName()
{
	s mTwo = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	s mThree = ##class(PHA.OP.MOB.TestThree).%New("测试")
	w mTwo.%ClassName(1),!
	w mTwo.%ClassName(0),!
	w mThree.%ClassName(1),!
	w mThree.%ClassName(0),!

	w mTwo.%PackageName(),!
	w mThree.%PackageName(),!
}
DHC-APP>d ##class(PHA.OP.MOB.Test).GetClassName()
2020-02-08
测试
PHA.OP.MOB.TestTwo
TestTwo
PHA.OP.MOB.TestThree
TestThree
PHA.OP.MOB
PHA.OP.MOB
 
DHC-APP>

克隆对象

要克隆一个对象,请调用该对象的%ConstructClone()方法。此方法创建一个新的OREF。
下面的终端会话演示了这一点:

SAMPLES>set person=##class(Sample.Person).%OpenId(1)
 
SAMPLES>set NewPerson=person.%ConstructClone()
 
SAMPLES>w
 
NewPerson=[[email protected]]
person=[[email protected]]
SAMPLES>
 
  

在这里,可以看到NewPerson变量使用的OREF与原始person对象不同。NewPerson是person的克隆(或者更准确地说,这些变量是指向分离但相同的对象的指针)。

相比之下,考虑下面的终端会话:

SAMPLES>set person=##class(Sample.Person).%OpenId(1)
 
SAMPLES>set NotNew=person
 
SAMPLES>w
 
NotNew=[[email protected]]
person=[[email protected]]
 
  

注意这里,两个变量都指向相同的OREF。也就是说,不是新不是克隆人。

/// d ##class(PHA.OP.MOB.Test).CloningObjects()
ClassMethod CloningObjects()
{
	s mTwo = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	s mTwoClone=mTwo.%ConstructClone()
	b
}
DHC-APP>d ##class(PHA.OP.MOB.Test).CloningObjects()
2020-02-08
测试
 
 b }
 ^
zCloningObjects+3^PHA.OP.MOB.Test.1
DHC-APP 2d1>zw
 

mTwo=[[email protected]]
mTwoClone=[[email protected]]
DHC-APP 2d1>zw
 
  

注意:克隆是表现的是不同的对象

引用实例的属性

要引用实例的属性,可以执行以下任何操作:

  • 创建关联类的实例,并使用点语法引用该实例的属性,如前所述。
  • 在关联类的实例方法中,使用相对点语法,如下所示:
..PropName

可以使用SET命令使用这个表达式,也可以将它用作另一个表达式的一部分。以下是一些变化:

 set value=..PropName
 write ..PropName

要访问属性(属性名直到运行时才确定),请使用$ property函数。如果属性是多维的,则在访问属性值时将属性名称后面的下列参数用作索引。的签名是:

$PROPERTY (oref, propertyName, subscript1, subscript2, subscript3... )
  • OREF 是对象
  • propertyName 计算结果为关联类中的属性方法的名称。
  • ubscript1, subscript2, subscript3 为属性的任何下标的值;仅为多维属性指定这些属性。
/// d ##class(PHA.OP.MOB.Test).TestPROPERTY()
ClassMethod TestPROPERTY()
{
	SET nlsoref=##class(%SYS.NLS.Locale).%New()
	WRITE $PROPERTY(nlsoref,"Language")
	s mTwo = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	WRITE $PROPERTY(mTwo,"value")
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestPROPERTY()
Simplified Chinese2020-02-08
测试
测试
DHC-APP>

注意:通过反射的方式设置属性值

  • (在实例方法中)使用变量$this,这将在本章后面介绍。
  • (在实例方法中)使用实例变量,这将在本章后面介绍。
  • 使用适用的属性访问器(getter和setter)方法。

调用实例的方法

要调用实例的方法,可以执行以下任何操作:

  • 创建关联类的实例,并使用点语法调用该实例的方法,如前所述。
  • (在一个实例方法中)调用该类的另一个实例方法(可以是一个继承的方法),使用以下表达式:
..MethodName(args)

可以使用DO命令来使用这个表达式。如果方法返回一个值,可以使用SET,或者将其用作另一个表达式的一部分。以下是一些变化:

 do ..MethodName()
 set value=..MethodName(args)

要执行一个实例方法,其中方法名直到运行时才确定,使用$method函数:

$METHOD(oref, methodname, Arg1, Arg2, Arg3, ... )
  • OREF 对象
  • methodname 计算结果为关联类中的实例方法的名称,
  • Arg1, Arg2, Arg3, and so on 方法的参数
    (在实例方法中)使用变量$this,这将在本章后面介绍。
/// d ##class(PHA.OP.MOB.Test).TestMethod()
ClassMethod TestMethod()
{

	s mTwo = ##class(PHA.OP.MOB.TestTwo).%New("测试")
	WRITE $METHOD(mTwo,"testonMethod")
}

DHC-APP>d ##class(PHA.OP.MOB.Test).TestMethod()
a
DHC-APP>

从实例获取类名

要获取类的名称,使用$CLASSNAME函数:

$CLASSNAME(oref)

oref 是对象

$this变量(当前实例)

$this语法提供了当前实例的OREF句柄,例如将它传递给另一个类,或者让另一个类引用当前实例的方法属性。当实例引用它的属性或方法时,相对点语法更快,因此是首选的。

t h i s 不 区 分 大 小 写 , this 不区分大小写, thisthis, $This, $THIS或任何其他变体都具有相同的值。

例如:假设有一个Accounting.Order 类和 Accounting.Utils 类, Accounting.Order.CalcTax() 方法调用Accounting.Utils.GetTaxRate()方法和Accounting.Utils.GetTaxableSubtotal() 方法,将当前实例的城市和状态传递给GetTaxRate()方法,并将已订购的项目列表和相关的税务相关信息传递给GetTaxableSubtotal()。然后CalcTax()使用返回的值来计算订单的销售税。因此,它的代码是这样的:

Method CalcTax() As %Numeric
{
   Set TaxRate = ##class(Accounting.Utils).GetTaxRate($this)
   Write "The tax rate for ",..City,", ",..State," is ",TaxRate*100,"%",!
   Set TaxableSubtotal = ##class(Accounting.Utils).GetTaxableSubTotal($this)
   Write "The taxable subtotal for this order is $",TaxableSubtotal,!
   Set Tax = TaxableSubtotal * TaxRate
   Write "The tax for this order is $",Tax,!
}

方法的第一行使用##class 语法(前面已经描述过)来调用另一个方法,它使用$this语法将当前对象传递给该方法。方法的第二行使用…获取City和State属性值的语法(前面也有描述)。第三行的动作与第一行相似。

在 Accounting.Utils和 GetTaxRate()方法可以使用传递的实例的句柄来获取各种属性的句柄,用于获取和设置它们的值:

ClassMethod GetTaxRate(OrderBeingProcessed As Accounting.Order) As %Numeric
{
   Set LocalCity = OrderBeingProcessed.City
   Set LocalState = OrderBeingProcessed.State
   // code to determine tax rate based on location and set
   // the value of OrderBeingProcessed.TaxRate accordingly
   Quit OrderBeingProcessed.TaxRate
}

GetTaxableSubtotal()方法还使用实例的句柄来查看其属性并设置其TaxableSubtotal属性的值。
因此,如果我们调用会计的MyOrder实例的CalcTax()方法 Accounting.Order,我们会看到这样的东西:

>Do MyOrder.CalcTax()
The tax rate for Cambridge, MA is 5%
The taxable subtotal for this order is $79.82
The tax for this order is $3.99

注意 ClassMethod 无法使用属性Property 只有Method方法才可以

Class PHA.OP.MOB.TestThree Extends %RegisteredObject
{

Property age;

ClassMethod testonMethod(my As PHA.OP.MOB.Test)
{
	q "this is testmethod"
}

}

Class PHA.OP.MOB.Test Extends %RegisteredObject
{
/// d ##class(PHA.OP.MOB.Test).TestThisKey()
ClassMethod TestThisKey()
{
 	s a=##class(PHA.OP.MOB.TestThree).testonMethod($this)
	
	WRITE a
}
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestThisKey()
this is testmethod

i% PropertyName(实例变量)

本节介绍实例变量。不需要引用这些变量,除非覆盖了属性的访问方法;

当创建任何类的实例时,Caché将为该类的每个未计算属性创建一个实例变量。实例变量保存属性的值。对于属性PropName,实例变量名为i%PropName,该变量名区分大小写。这些变量在类的任何实例方法中都是可用的。

例如,如果一个类有属性Name和DOB,那么实例变量i%Name和i%DOB在该类的任何实例方法中都是可用的。
在内部,Caché也使用了额外的实例变量,比如r%PropName和m%PropName,但是不支持直接使用。
实例变量有分配给它们的进程私有内存存储。注意,这些变量不在局部变量符号表中,也不受Kill命令的影响。

Method %OnNew(initvalue As %String) As %Status [ Private, ServerOnly = 1 ]
{
	s ..value=initvalue
    s ..date=$zd(+$h,3)
    w ..date,!
    w ..value,!
    w "i%value:"_i%value,!
    w "i%date:"_i%date,!
    w "i%address:"_i%address,!
    Quit $$$OK
}
DHC-APP> d ##class(PHA.OP.MOB.Test).TestPROPERTY()
Simplified Chinese2020-02-08
测试
i%value:测试
i%date:2020-02-08
i%address:
测试
DHC-APP>

注意 :i% PropertyName仅在实例方法中可用,类方法不可用(静态方法)

你可能感兴趣的:(Caché,从入门到精通)