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

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


复杂类型的子类型 #

简单类型的子类型化已在 2.5.1 节(ObjectTypes)和 2.5.2 节(VariableTypes)中进行了说明。对于变量类型,数据类型的使用可以在子类型中受到限制,因此子类型只能使用与超类型中定义的相同的数据类型,包括对数组大小的限制等。因此,客户端知道他们可以像使用超类型一样使用子类型。

关于复杂类型的子类型化,必须满足相同的保证。当复杂类型被子类型化时,仍然必须满足超类型的基本特征。因此,强制性的 InstanceDeclaration 也必须在子类型的每个实例上有效。一般来说,超类型的每个约束也必须在子类型上得到满足,并且只能进一步限制。这意味着可选的 InstanceDeclaration 可以在子类型上成为强制性的,但不能将强制性的 InstanceDeclaration 设为可选的。

在地址空间中公开复杂类型的子类型有两种可能。由于超类型的每个 InstanceDeclaration 在子类型上都有效,因此一种解决方案是每个子类型复制超类型的所有 InstanceDeclaration 或引用相同的节点。另一种解决方案是它们不被复制,但客户端也需要请求超类型的 InstanceDeclarations 才能获得子类型的全貌。第二种方法通常用于面向对象的编程语言,其中继承超类型的变量而无需将代码复制到子类型。OPC UA 也选择了第二种方法,以避免在具有多个级别的类型层次结构中节点爆炸。因此,除非您想要覆盖它们,否则不必在子类型上重复 InstanceDeclarations。在图 1.26 中,显示了复杂类型的子类型与面向对象类的子类型的比较。面向对象的类 Address 由 InternationalAddress 子类型化。这里只添加了一个额外的变量 Country,其他变量没有指定,但由 Address 继承。ObjectType InternationalAddressType 也适用同样的方法。只添加了 InstanceDeclaration Country,其他 InstanceDeclarations 都是继承的。要获得 TypeDefinition 的完整图景,您需要将超类型的 InstanceDeclarations 与 TypeDefinition 结合起来。这种组合称为完全继承的 InstanceDeclarationHierarchy,如图 1.26 中 InternationalAddressType 所示。这里捕获了所有信息,以便针对类型进行编程或了解至少需要实例化什么。

面向对象类和复杂类型的子类型

要使用完全继承的 InstanceDeclarationHierarchy,所有 InstanceDeclarations 都必须具有唯一的 BrowsePaths。因此,子类型不能对不同的 InstanceDeclaration 使用相同的 BrowsePath。但是,子类型能够覆盖超类型的现有 InstanceDeclaration(图 1.27)。例如,在InternationalAddressType中,可能需要提供 Street。因此,ModellingRule Optional 不再适用。正如我们之前所了解的,允许在 InstanceDeclaration 中将 Optional 更改为 Mandatory。对于子类型也是如此。因此,修改后的 InternationalAddressType 将创建自己的 Street 变量并将其定义为强制性的。由于在超类型中使用了相同的 BrowsePath,因此它不是额外的 InstanceDeclaration,而是 InternationalAddressType 的 InstanceDeclaration 覆盖了 AddressType 的 InstanceDeclaration。因此,完全继承的 InstanceDeclarationHierarchy 仍然只有一个 Street 变量,但这次 ModellingRule 已经发生了变化,因为使用了重写的 InstanceDeclaration。在 [UA 第 3 部分] 中,定义了如何获取完全继承的 InstanceDeclarationHierarchy 的详细算法,考虑了超类型链。

当然,在重写 InstanceDeclarations 时必须应用一些规则。一般来说,约束只能收紧,不能放松。这意味着必须使用与重写的 InstanceDeclaration 相同的类型或子类型,并且 ModellingRules 只能受到进一步限制。例如,如果有一个约束 ModellingRule 规定 Reference 必须存在 3-6 次,则允许增加下限并减少上限,但不能反过来。所以 4-5 是允许的,2-5 或 4-8 是不允许的。

在对复杂 TypeDefinitions 进行子类型化时覆盖 InstanceDeclarations

让我们考虑另一个使用更复杂的 InstanceDeclarationHierarchy 进行子类型化和覆盖的示例。在图 1.28 中,我们已经在图 1.23 中引入了 TemperatureSensorType。EngineeringUnit 变量由两个 BrowsePath 以及 Temperature 变量引用。子类型 MyTemperatureSensorType 派生自 TemperatureSensorType。在此子类型中,必须将 Temperature 的可选 EngineeringUnit 设为强制项。由于 EngineeringUnit 变量未直接由 ObjectType 引用,因此无法直接覆盖它。相反,必须覆盖 EngineeringUnit 路径上的第一个 InstanceDeclaration,并且必须复制该节点下 EngineeringUnit 的完整路径才能覆盖 EngineeringUnit。在图 1.28 中,您可以看到从 Measurement 开始的路径以及 Temperature 变量被覆盖,在其下方是 EngineeringUnit,将其 ModellingRule 更改为 Mandatory。

让我们看看这对于完全继承的 InstanceDeclarationHierarchy 意味着什么。如您所见,子类型中仅提供了 ObjectType 和 Measurement 之间的一个引用。但是,由于两个引用必须始终引用同一个节点,因此它们引用完全继承的 InstanceDeclarationHierarchy 中的一个节点。EngineeringUnit 可通过超类型中的两个路径访问,并且只在一个路径中覆盖。在这种情况下,完全继承的 InstanceDeclarationHierarchy 必须复制 EngineeringUnit,对于覆盖的路径提供更改的 ModellingRule,对于未覆盖的路径提供原始的 ModellingRule。请注意,尽管完全继承的 InstanceDeclarationHierarchy 引用了两个称为 EngineeringUnit 的不同节点,但 MyTemperatureSensorType 的实例可以在两个路径中引用同一个节点。

在 OPC UA 中,每个 ObjectType 必须是 [UA 第 5 部分] 中定义的 BaseObjectType 的子类型,因此只有一个类型层次结构。规范并未将类型层次结构限制为单继承。因此,多继承(即具有多个超类型)是一种选择。但是,规范仅指定了单继承的规则(仅复杂类型需要)[5]。因此,建议尽可能使用单继承。

覆盖具有多个 BrowsePaths 的 InstanceDeclarations

复杂的 TypeDefinitions 具有具有唯一 BrowsePaths 的 InstanceDeclarations。ModellingRules 定义了 TypeDefinitions 实例上允许的内容和不允许的内容。

实例可以具有指向不同节点的相同 BrowsePath;TranslateBrowsePathsToNodeIds 服务可用于根据 TypeDefinition 收集节点。

OPC UA 定义了一个开放模型。只要它不受 TypeDefinition 上的某些约束定义,就可以向 TypeDefinition 的实例添加引用,从而向这些实例添加变量、方法等。但是,服务器可能始终限制这些功能,而无需在 TypeDefinition 上明确说明它们。

在对 TypeDefinitions 进行子类型化时,必须始终保证仍然满足超类型的约束。这包括 ModellingRules 的语义、变量的数据类型以及任何其他约束。

可以通过在子类型中提供相同的 BrowsePath 来覆盖 InstanceDeclarations。

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