第一章 IRIS 类编程思想

本书介绍了如何在InterSystems IRIS®数据平台中创建和使用类,特别是定义对象的类。

如果您不熟悉类编程,本章旨在让您了解此类编程的工作原理。如果您熟悉类编程,您可能会发现浏览代码示例很有用,这样您就可以看到InterSystems IRIS中的类编程是什么样子了。

本章中的概念在很大程度上独立于语言,尽管示例使用ObjectScript。

1.1 对象和属性

在类编程中,一个关键概念是对象。对象是一组值的容器,这些值存储在一起或作为集合一起传递。对象通常对应于现实生活中的实体,例如患者、患者诊断、事务等等。

类定义通常是给定类型对象的模板。类定义具有包含这些对象的值的属性。例如,假设我们有一个名为 MyApp.Clinical.PatDiagnosis 的类;此类可以具有属性DateEnteredByPatientIDDiagnosedByCode等。

通过创建类的实例来使用模板;这些实例是对象。例如,假设用户将患者诊断输入用户界面并保存该数据。基础代码将具有以下逻辑:

  1. 从患者诊断模板创建新的患者诊断对象。

  2. 根据需要设置对象属性的值。有些可能是必需的,有些可能具有默认值,有些可能基于其他值计算,有些可能是纯可选的。

  3. 保存对象。

    此操作存储数据。

下面显示了使用ObjectScript的示例:

//创建对象
 set diagnosis=##class(MyApp.Clinical.PatDiagnosis).%New()

 //使用特殊变量设置几个属性
 set diagnosis.Date=$SYSTEM.SYS.TimeStamp()
 set diagnosis.EnteredBy=$username
 
 //根据用户界面变量设置其他属性
 set diagnosis.PatientID=patientid
 set diagnosis.DiagnosedBy=clinicianid
 set diagnosis.Code=diagcode
 
 //保存数据
 //下一行尝试保存数据并返回状态以指示行动是否成功
 set status=diagnosis.%Save()
 //始终检查返回的状态
 if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status}

注意以下几点:

  • 要引用对象的属性,可以使用语法object_variable.propertiesname,例如:diagnosis.DiagnosedBy

  • %New()%Save()MyApp.Clinical.PatDiagnosis 类的方法。

下一节将讨论方法的类型以及为什么要以不同的方式调用它们。

1.2 方法

方法是一个过程(在大多数情况下,InterSystems IRIS支持其他类型的方法,您将在下一章中看到)。方法可以相互调用,可以引用属性和参数。

类语言中有两种方法:实例方法和类方法。它们有不同的目的,以不同的方式使用。

1.2.1 实例方法

实例方法只有在从类的实例调用时才有意义,通常是因为您正在对该实例执行某些操作。例如:

 set status=diagnosis.%Save()

例如,假设我们正在定义一个表示患者的类。在这个类中,我们可以定义实例方法来执行以下操作:

  • 计算患者的BMI(体重指数)
  • 打印汇总患者信息的报告
  • 确定患者是否符合特定程序的要求

这些操作中的每一个都需要了解为患者存储的数据,这就是为什么大多数程序员会将它们作为实例方法来编写的原因。在内部,实例方法的实现通常引用该实例的属性。下面显示了引用两个属性的实例方法的示例定义:

Method GetBMI() as %Numeric
{
 Set bmi=..WeightKg / (..HeightMeter*2)
 Quit bmi
}

要使用此方法,应用程序代码可能包括以下行:

 //根据id打开请求的患者
 set patient=##class(MyApp.Clinical.PatDiagnosis).%OpenId(id)  
 
 //获取要在BMI显示字段中显示的值 
 set BMIDisplay=patient.GetBMI() 

1.2.2 类方法

另一种类型的方法是类方法(在其他语言中称为静态方法)。要调用这种类型的方法,可以使用不引用实例的语法。例如:

 set patient=##class(MyApp.Clinical.PatDiagnosis).%New()

编写类方法有三个非常普遍的原因:

  • 您需要执行创建类实例的操作。

    根据定义,此操作不能是实例方法。

  • 您需要执行影响多个实例的操作。

    例如,您可能需要将一组患者重新分配给不同的初级护理医生。

  • 您需要执行不影响任何实例的操作。

    例如,您可以编写一个方法,返回一天中的时间、随机数或以特定方式格式化的字符串。

1.2.3 变量作用域

方法通常设置变量的值。在几乎所有情况下,这些变量仅在该方法中可用。例如,考虑以下类:

Class GORIENT.VariableScopeDemo
{

ClassMethod Add(arg1 As %Numeric, arg2 As %Numeric) As %Numeric
{
    Set ans=arg1+arg2
    Quit ans
}

ClassMethod Demo1()
{
   set x=..Add(1,2)
   write x
}

ClassMethod Demo2()
{
   set x=..Add(2,4)
   write x
}

}

Add() 方法设置一个名为ans的变量,然后返回该变量中包含的值。

方法 Demo1() 使用参数1和2调用方法 Add() ,然后写入答案。方法 Demo2() 类似,但使用不同的硬编码参数。

如果方法 Demo1()Demo2() 试图引用变量ans,则该变量在该上下文中未定义,InterSystems IRIS将抛出错误。

类似地, Add() 不能引用变量x。此外, Demo1() 中的变量x与 Demo2() 中变量x是不同的变量。

这些变量的范围有限,因为这是InterSystems IRIS类的默认行为(也是其他类语言中的常见行为)。

在类定义中,几乎完全通过将值作为参数包含到方法中来传递值。这是类编程中的惯例。这种约定简化了确定变量范围的工作。

相反,在编写例程时,有必要了解控制范围的规则。这些在使用ObjectScript中进行了讨论。

1.3 常量

有时,类可以轻松访问常量值是很有用的。在InterSystems IRIS类中,这样的值是一个类参数。其他语言则使用类常量这一术语。以下是一个示例:

Parameter MYPARAMETER = "ABC" ;

类常量在编译时获取值,以后不能更改。

您的方法可以引用常量;这就是定义常量的原因。例如:

 set myval=..#MYPARAMETER * inputvalue

1.4 类定义和类型

下面是一个类定义的示例,我们将使用它来讨论类定义中的类型:

Class MyClass Extends %Library.Persistent
{
Parameter MYPARAMETER = "ABC" ; 

Property DateOfBirth As %Library.Date; 

Property Home As Sample.Address; 

Method CurrentAge() As %Library.Integer 
{
 //details
}

ClassMethod Addition(x As %Library.Integer, y As %Library.Integer) As %Library.Integer
{
 //details
}

}

这个类定义定义了一个参数( MYPARAMETER )、两个属性( DateOfBirthHome )、一个实例方法( CurrentAge() )和一个类方法( Addition() )。

在类编程中,可以在以下关键位置指定类型:

  • 对于类本身。Extends后面的元素是一种类型。

    每种类型都是类的名称。

  • 对于参数。在本例和其他情况下,As后面的元素是一种类型。

  • 对于属性。对于Home属性,类型是一个本身包含属性的类。

    在这种情况下,类型具有对象值。在这里的示例中,这是一个对象值属性。

    对象值属性可以包含其他对象值属性。

  • 用于方法的返回值。

  • 用于方法使用的任何参数的值。

1.5 继承

在大多数基于类的语言中,一个主要特性是继承:一个类可以从其他类继承,从而获得其他类的参数、属性、方法和其他元素。参数、属性、方法和其他元素统称为类成员。

1.5.1 术语和基础

当类A从类B继承时,我们使用以下术语:

  • 类A是类B的子类。或者,类A扩展了类B。

    有时有人说A类是B类的一个子类。

  • B类是A类的超类。

    有时有人说A类是子类,B类是父班。这个术语很常见,但可能会误导人,因为在讨论SQL表时,父级和子级这两个词的使用意义截然不同。

当一个类从其他类继承时,它获取这些其他类的类成员,包括超类自身继承的成员。子类可以重写继承的类成员。

一个类的多个超类可以定义同名的方法、同名的属性等。因此,有必要制定规则来决定哪个超类提供了子类中使用的定义。

在InterSystems IRIS类库中,超类通常有不同的用途,并且具有不同名称的成员,成员名称的冲突并不常见。

1.5.2 示例

以下是InterSystems IRIS的示例:

/// 查找FilePath目录中的文件,并将所有与FileSpec通配符匹配的文件提交给用于在InterSystems IRIS中处理的相关业务服务 
Class EnsLib.File.InboundAdapter Extends (Ens.InboundAdapter, EnsLib.File.Common) 

这个例子只是为了演示一个类如何组合来自不同超类的逻辑。这个 EnsLib.File.InboundAdapter 可类中继承了两个执行完全不同任务的类:

  • Ens.InboundAdapter ,其中包含“入站适配器”的基本逻辑,这是InterSystems IRIS中的一个概念。
  • EnsLib.File.Common ,其中包含处理给定目录中的文件集的逻辑。

EnsLib.File.InboundAdapter ,方法使用这两个类及其超类的逻辑。

1.5.3 继承类成员的使用

当您在编辑工具中看到类的定义时,您不会看到它包含的继承成员,但代码可以引用它们。

例如,假设类A有两个属性,每个属性都有一个默认值,如下所示:

Class Demo.A  
{
Property Prop1 as %Library.String [InitialExpression = "ABC"];

Property Prop2 as %Library.String [InitialExpression = "DEF"];
}

B类可能是这样的:

Class Demo.B Extends Demo.A  
{
Method PrintIt()
{
 Write ..Prop1,! 
 Write ..Prop2,! 
}

}

如前所述,子类可以覆盖继承的类成员。例如,类C也可以从类A继承,但可以覆盖其属性之一的默认值:

Class Demo.C Extends Demo.A  
{
Property Prop2 as %Library.String [InitialExpression = "GHI"];

}

1.5.4 子类的使用

如果类B继承自类A,则可以在可以使用类A实例的任何位置使用类B的实例。

例如,假设您有如下实用程序方法:

ClassMethod PersonReport(person as MyApp.Person) {
 //print a report that uses properties of the instance
}

您可以使用 MyApp.Person 的实例作为此方法的输入。您还可以使用 MyApp.Person 的任何子类的实例。例如:

 //id variable is set earlier in this program 
 set employee=##class(MyApp.Employee).%OpenId(id)
 do ##class(Util.Utils).PersonReport(employee)

类似地,方法的返回值(如果它返回值)可以是指定类型的子类的实例。例如,假设 MyApp.EyeeMyApp.Peater 都是 MyApp.Person的子类。您可以定义如下方法:

ClassMethod ReturnRandomPerson() as MyApp.Person
{
 Set randomnumber = $RANDOM(10)
 If randomnumber > 5 {
     set person=##class(MyApp.Employee).%New()
 }
 else {
     set person=##class(MyApp.Patient).%New()
 }
 quit person
}

1.6 类作为方法的容器

如前所述,类定义通常是对象的模板。另一种可能性是类是一组属于一起的类方法的容器。在这种情况下,您永远不会创建此类的实例。您只能在其中调用类方法。

例如,请参阅InterSystems IRIS%SYSTEM包中的类。

1.7 抽象类

定义抽象类也很有用。抽象类通常定义通用接口,并且不能实例化。类中的方法定义声明方法的签名,但不声明其实现。

定义一个抽象类来描述接口。然后您或其他开发人员创建子类,并在这些子类中实现方法。实现必须与抽象类中指定的签名匹配。该系统使您能够开发多个目的略有不同但接口相同的并行类。出于这个原因,许多系统类都有公共接口。

即使类不是抽象的,也可以指定方法是抽象的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值