注:Caché 遇到不包含包名的类的引用,并且类名以“%”开头时,则该类在“%Library”包中。
Caché 支持包,包将特定数据库中的相关类分组。包提供以下好处:
包只是一种将相关类分组到公共名称下的方法。例如,一个应用程序可以有一个“Accounting”系统和一个“Inventory”系统。组成这些应用程序的类可以组织成一个“Accounting”包和一个“Inventory”包:
这些类中的任何一个都可以使用它们的全名(由包名和类名组成)来引用:
Do ##class(Accounting.Invoice).Method()
Do ##class(Inventory.Item).Method()
如果包名可以通过上下文确定,那么包名可以省略:
Do ##class(Invoice).Method()
与类一样,包定义存在于Caché 数据库中。有关将包从数据库映射到名称空间的信息
包名是一个字符串。它可能包含“.”字符,但不能有其他标点符号。包名以"."分割,每个部分都是一个子包,并且可以有多个子包。如果给一个类命名为Test.Subtest。TestClass,然后这表明包的名称是Test,子包的名称是子Test,类的名称是TestClass。
包名的长度和用法有几个限制:
包由类的名称来暗示。创建一个类时,包被自动定义。类似地,当删除包中的最后一个类时,也会自动删除包。
下面是一个示例,其中包名是Accounting,类名是Invoice,完全限定的类名是Account .Invoice:
Class Accounting.Invoice
{
}
根据定义,每个包都是特定数据库的一部分。通常,每个数据库都与一个名称空间相关联,其中数据库和名称空间共享一个公共名称。这适用于系统提供的各种数据库和名称空间,例如sample和USER。要使数据库中的包定义对与该数据库无关的名称空间可用,请使用包映射。
下面的过程将包含包的数据库称为“源数据库”,将包映射到的名称空间称为“查看命名空间”。映射一个包的过程是:
注意:在映射包时,一定要标识包中的类使用的任何包含文件。如果这些包含文件的名称不是以%开头的,那么它们在所有名称空间中都不可用,也必须映射它们(通过例程映射页面),以便类能够找到它们。类似地,确保映射类使用的所有例程和类在目标名称空间中可用。
当映射一个包时,映射应用于包中的类定义和生成的例程,它们位于同一个包中。
Caché 还提供通过单个操作使源包在多个目标名称空间中可用的功能。这样的映射使包在除了DOCBOOK和SAMPLES之外的所有名称空间中都可用。
要使一个包对多个名称空间可用,过程如下:
注意:删除%ALL名称空间将删除其映射。
有两种方法来引用类:
// create an instance of Lab.Patient
Set patient = ##class(Lab.Patient).%New()
默认情况下,当使用一个简短的类名时,Caché 会假定这个类在所使用的类的包中(如果有的话),或者在%Library包中,或者在User包中。
如果希望编译器搜索其他包中的类,请按照下一节的描述导入这些包。
注意:使用一个模糊的短类是错误的;也就是说,如果在两个或多个包中有相同的短类名,并将它们全部导入,那么当编译器试图解析包名时,将得到一个错误。要避免此错误,请使用全名。
当导入包时,Caché 会在这些包中查找任何短的类名。
可以在类定义的顶部,类行之前包含类导入指令。该指令的语法如下:
Import packages
Class name {}
其中包是单个包或包的逗号分隔列表,括在括号中。Import这个词不区分大小写,但通常是大写的,如下所示。请记住,在类上下文中,当前包总是隐式导入的。
Import (SQLUser,PHA.OP.MOB.Android)
/// w ##class(PHA.IP.MOB.Business).test("自煎","饭后温服") "N"
/// w ##class(PHA.IP.MOB.Business).test("代煎","饭后温服") "Y"
/// w ##class(PHA.IP.MOB.Business).test("代煎","加工膏滋") "N"
/// w ##class(PHA.IP.MOB.Business).test("自煎","加工膏滋") "N"
ClassMethod test(a, b)
{
;d ..importPackage()
s a=##class(Android).Login("demo#1")
w a,!
b
s ret="N"
i (a'="自煎")&&(b'="加工膏滋") d
.s ret="Y"
q ret
}
ClassMethod importPackage()
{
;#import PHA.OP.MOB
w "bbb",!
}
在Cache ObjectScript方法中,#IMPORT指令导入一个包,这样就可以使用简短的类名来引用其中的类。该指令的语法如下:
#import packagename
其中packagename是包的名称。单词#import不区分大小写。例如:
#import Lab
// Next line will use %New method of Lab.Patient, if that exists
Set patient = ##class(Patient).%New()
可以有多个#IMPORT指令:
#import Lab
#import Accounting
// Look for "Patient" within Lab & Accounting packages.
Set pat = ##class(Patient).%New()
// Look for "Invoice" within Lab & Accounting packages.
Set inv = ##class(Invoice).%New()
#IMPORT指令的顺序对编译器解析短类名的方式没有影响。
一旦代码显式地导入任何包,用户包就不会自动导入。如果需要该包,还必须显式地导入它。例如:
#import MyPackage
#import User
这种逻辑的原因是,在某些情况下,可能不希望导入用户包。
类继承从父类中显式导入的包。类的名称在最初使用它的上下文中解析,而不是与当前类的名称一起解析。例如,假设在User中定义。然后创建一个MyPackage。继承自User的MyClass类。然后编译它。Caché 编译MyPackage中继承的MyMethod()方法。MyClass——但是解析User上下文中此方法中的任何类名。MyClass(因为这个方法就是在这里定义的)。
通过导入包,可以生成适应性更强的代码。例如,您可以创建如下代码:
#import Customer1
Do ##class(Application).Run()
现在将App.MAC更改为:
#import Customer2
Do ##class(Application).Run()
重新编译App.MAC时,将使用Customer2。应用程序类。这样的代码必须考虑代码的兼容性以及对存储结构的影响。