第二章:信息建模:对象和变量的类型2

REDISANT 提供互联网与物联网开发测试套件 #


复杂对象类型 #

复杂 ObjectType 定义了其下的 Node 结构,该结构也可用于 ObjectType 的每个实例。图 1.14 给出了一个复杂 ObjectType 的示例。MotorType 具有方法 Start 和 Stop、Status变量和一个名为 Configuration 的对象,该对象具有两个变量。图 1.14 显示 MotorType 的实例(如 Motor1)在其下具有相同的结构。

在我们更详细地了解复杂 ObjectType 的工作原理之前,让我们讨论一下我们为什么可能需要复杂 ObjectType。服务器公开复杂 ObjectType 和该类型的实例,使客户端能够根据类型信息编写应用程序,并在所有实例上使用它。例如,客户端可以拥有针对 ObjectType 量身定制的用户界面的特定部分,并为该类型的每个实例显示它。图 1.15 总结了这种情况。

复杂 ObjectType 的示例

客户端的图形元素是使用 MotorType 知识进行编程的。在客户端的用户界面中,此图形元素使用了两次,代表 MotorType 的两个实例,称为 Motor1 和 Motor2。关于类型的知识用于访问和显示实例提供的信息。使用关于类型的知识并不局限于复杂的 ObjectType。例如,客户端可以通过在树形控件中使用特定图标来实现对 FolderType 的特殊处理。然而,当使用复杂类型的知识进行编程时,考虑到类型下的节点结构,真正的力量就会发挥作用。

针对复杂 ObjectType 进行编程

拥有复杂 ObjectType 的另一个优点是它们只需定义一次,就可以在多个地方使用。当服务器创建 ObjectType 的新实例时,可以保证它具有 ObjectType 定义的结构。ObjectType 可以在多次使用的项目中、特定于供应商的库中甚至标准信息模型中定义。可以使用 AddNodes 服务实例化 ObjectType 的多个实例(参见第 5 章)。只需指定实例的 ObjectType 和基本属性。此场景如图 1.16 所示。客户端调用 AddNodes 服务来创建新的对象 Motor1。基于此调用的所有新创建的节点和引用都以粗线样式显示。在 AddNodes 服务中,客户端必须指定新节点应连接到的 ReferenceType 和节点。在我们的示例中,选择了 Area1 对象和 Organizes ReferenceType。此外,它还指定了新节点的属性(如 DisplayName Motor1),并指定了 ObjectType。根据指定的 ObjectType,将创建对 ObjectType 的 HasTypeDefinition 引用,并在新对象下自动创建由 ObjectType 定义的结构。

根据复杂对象类型创建实例

InstanceDeclaration #

在解释了为什么复杂的 ObjectType 是一个非常有用的功能之后,让我们更仔细地研究一下它们。如图 1.14 所示,ObjectType MotorType 使用 ObjectType 节点类。它下面的所有节点都是对象、变量或方法节点类,因此是实例而不是类型。但是,它们通常不是具有真实值的真实实例,因此它们被称为 InstanceDeclarations。InstanceDeclaration 是用于定义复杂 ObjectType 的命名实体。InstanceDeclarations 被定义为 ObjectType 下公开的变量、对象和方法。由于在公开多个层次结构的全网状节点网络中,某些东西的下方并不那么明显,因此更精确的定义是 InstanceDeclarations 被 ObjectType 中的层次结构类型的引用所引用(向前引用),或直接或间接地由另一个 InstanceDeclaration 引用。此外,InstanceDeclaration 必须具有 ModellingRule(参见第 2.5.6 节)。

InstanceDeclarations 的一个关键特性是它们可以相对于 ObjectType 进行唯一标识。相同的相对标识符适用于 ObjectType 的实例和 InstanceDeclaration 的对应部分。这允许使用 ObjectType 的知识进行编程。NodeId 不能用于此目的,因为 InstanceDeclaration 通常与实例上的对应部分不同,因此必须具有不同的 NodeId。相反,使用 BrowseName,或者对于间接引用的 InstanceDeclarations,使用 BrowsePath,它是 BrowseName 的列表。这要求 InstanceDeclaration 必须具有从 ObjectType 开始的唯一 BrowsePath。该路径必须与 NodeClass 无关,是唯一的,这意味着 ObjectType 不能将具有相同 BrowseName 的对象和变量直接引用为 InstanceDeclaration。BrowsePath 在图 1.17 中举例说明。

InstanceDeclarations 的唯一BrowsePath

客户端可以检测从 ObjectType 开始并向前遵循层次化引用的 InstanceDeclaration 的 BrowsePath。它们必须在到达目标 InstanceDeclaration 之前添加每个节点的 BrowseName。客户端可以存储该信息,当它们要访问 ObjectType 的具体实例时,它们可以调用一个名为 TranslateBrowsePathsToNodeIds 的特殊服务(有关详细信息,请参阅第 5 章)。此服务将实例的 NodeId 和 BrowsePath 作为输入,并返回 InstanceDeclaration 对应部分的 NodeId。通过使用此 NodeId,客户端可以对节点执行适当的操作,例如订阅数据或写入数据。

请注意,对唯一 BrowseName 的约束仅适用于 InstanceDeclarations,而不适用于实例。在图 1.18 中,您可以看到 MotorX 引用另一个Configuration对象,该对象包含默认Configuration设置,其 BrowseName 与基于 MotorType 的Configuration对象相同。在这种情况下,TranslateBrowsePathsToNodeIds 服务将返回一个 NodeIds 数组,其中基于 TypeDefinition 的节点的 NodeId 作为第一个条目。

实例的非唯一BrowsePath

具有 InstanceDeclarations 的复杂 ObjectType 与具有变量的面向对象编程语言中的类非常相似。在类中,变量是一个通过名称寻址的命名实体。让我们看一个面向对象类的示例,以及如何轻松地将其映射到复杂 ObjectType。图 1.19 中,Employee 类以伪代码显示。该类具有公开变量 Name、Salary 和 Address。为简单起见,名称只是一个字符串,Salary 是一个整数,但地址使用另一个具有公开变量 Street 和 City 的 Address 类。此外,Employee 有两个方法,IncreaseSalary() 和 SalaryAfterTax()。第一个方法采用百分比并增加员工的工资;第二个方法返回员工的税后工资。映射到 ObjectType 很简单。Address 类映射到具有两个变量的 ObjectType AddressType。Employee 类映射到具有两个变量(Salary 和 Name)以及一个表示 Address 的 AddressType 实例的 ObjectType EmployeeType[3]。此外,还有两个方法IncreaseSalary和SalaryAfterTax,一个只有输入参数和说明,另一个只有输出参数。

将面向对象的类映射到 ObjectType

当然,典型的面向对象编程语言的类和 ObjectType 之间也存在差异。一个区别是没有标准的方式来公开方法的实现。另一方面,OPC UA 更灵活。允许向独立于类型定义的实例添加组件。例如,Employee 的实例可以有一个名为 Award 的变量,用于存储有关员工收到的奖励的信息,而无需更改 ObjectType 或创建其子类型。在 InstanceDeclarations 上也允许这样做,因此 EmployeeType 可以在 Address 对象下添加变量 ZipCode。在面向对象的编程语言中,通常必须将 Address 子类型化才能在该位置添加信息。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.redisant.cn