OPC UA defines a type model supporting one object-oriented type hierarchy for ObjectTypes. Although the specification does not restrict those hierarchies to be single inheritance (i.e. a type can only have one super-type) it only specifies the semantic (inheritance rules) for single inheritance.
In general, good object-oriented design is accomplished by using composition to aggregate an object which provides several functions instead of over-using inheritance [GH95], [FF04] .
Interfaces and AddIns complement the type model and can be used when subtyping is not suitable for the required extension. They:
- allow enhancing multiple types at arbitrary positions in the type hierarchy.
- also allow enhancing just instances.
Interfaces are ObjectTypes that represent a generic feature (functionality), assumed to be usable by different ObjectTypes or Objects. The Interface model specifies the rules and mechanisms to achieve this.
The “InterfaceTypes” Object (see OPC 10000-5) has been defined so that all Interfaces of the Server are either directly or indirectly accessible browsing HierarchicalReferences starting from this Node.
Rules for the definition of Interfaces:
- Interface ObjectTypes shall be abstract subtypes of the BaseInterfaceType ObjectType.
- InstanceDeclarations on an Interface shall only have ModellingRules Optional or Mandatory.
- Interfaces can be subtyped as specified in clause 6.3.
- Interfaces shall not be the source of HasInterface References.
- Recommended convention: The first letter of an Interface should be ‘I’. See examples below.
Rules for applying Interfaces:
- When an ObjectType references an Interface with a HasInterface Reference or a subtype, the following rules apply:
- Each mandatory InstanceDeclaration of the fully-inherited InstanceDeclarationHierarchy of the Interface shall have for each BrowsePath a similar Node (see 6.2.4) with the ModellingRule Mandatory using the same BrowsePath in the fully-inherited InstanceDeclarationHierarchy of the ObjectType. The rules for instantiating InstanceDeclarations defined in 6.2.6 shall be applied.
- Each optional InstanceDeclaration of the fully-inherited InstanceDeclarationHierarchy of the Interface should have for each BrowsePath a similar Node (see 6.2.4) with the ModellingRule Mandatory or Optional using the same BrowsePath in the fully-inherited InstanceDeclarationHierarchy of the ObjectType. The rules for instantiating InstanceDeclarations defined in 6.2.6 shall be applied. If no similar Node with the same BrowsePath exists, the ObjectType and its sub-types shall not use the same BrowsePath for a different Node (e.g. with a different NodeClass).
If the rules cannot be fulfilled (e.g. name collisions) the ObjectType cannot apply the Interface, i.e. it shall not reference the Interface with a HasInterface Reference of a subtype.
The rules apply for each referenced Interface. As a consequence, an ObjectType cannot reference two Interfaces using the same BrowsePath for Nodes that are not similar Nodes or have TypeDefinitionNodes that are not compatible (compatible means they have either the same TypeDefinitionNode or one TypeDefinitionNode is the subtype of the other TypeDefinitionNode).
- Subtypes should not have a HasInterface Reference to an Interface if it was already applied to a super-type.
- When an Object references an Interface with a HasInterface Reference or a subtype, the following rules apply:
- The Interface shall not be applied on the Object when the Interface cannot be applied on the TypeDefinitionNode of the Object.
- The same rules on the Object apply as if the Interface would have been applied on the TypeDefinitionNode of the Object (e.g. all Mandatory InstanceDeclarations need to be applied).
- The Nodes defined based on the Interface shall be handled as if they were defined by the TypeDefinitionNode. For example, the TranslateBrowsePathsToNodeIds Service shall return them first.
- If several Interfaces should be applied to the Object, they should be treated as if they were all applied to the ObjectType of the Object at the same time. If this is not possible, the Interfaces cannot be applied to the Object together.
- Instances should not have a HasInterface Reference to an Interface if it was already applied to the TypeDefinitionNode.
- A BaseInterfaceType or any subtype of BaseInterfaceType shall not be the TargetNode of a HasTypeDefinition Reference.
Figure 8 illustrates example Interfaces:
- ISerializeServiceType, an Interface to convert the Object and its components into a stream of bytes.
- ITransactionServiceType, an Interface to perform a sequence of changes to the Object as a single operation.
- ILocationType, an Interface to specify the installation location of the Object.
Figure 8 – Examples of Interfaces
The following examples illustrate the application of these Interfaces. In Figure 9 the example Interface ILocationType is applied to the XYZ-DeviceType ObjectType. It also illustrates the overriding of Property “Address” by changing the ModellingRule from Optional to Mandatory. Figure 10 in addition shows how to use the ISerializeService Interface on the instance only. Figure 11 shows an Interface hierarchy where InstanceDeclarations of the referenced Interface and its parent type(s) are applied (the fully-inherited InstanceDeclarationHierarchy).
Figure 9 – Example: Interface application to an ObjectType
Figure 10 – Example: One Interface applied to an ObjectType another one to the instance
Figure 11 – Example: Interface Hierarchy
Clients can detect the implementation of Interfaces by filtering for the HasInterface Reference into the Browse Service request.
On instances, the Browse Service will return elements derived from an Interface together with elements of the Node’s base type. Clients can also use the TranslateBrowsePathsToNodeId Service with BrowseNames of Interface members to get the NodeId of these members directly.
In the example in Figure 10 “Address” with the starting node MD002 can be used to request the NodeId of this Property.
On Object instances, some Nodes of an Interface may not be available if defined with ModellingRule Optional.
AddIns associate a feature or feature-set, represented by an ObjectType to the Node (an Object or ObjectType) they are applied to. The Interface model is different than the AddIn model in that it is based on composition. An AddIn is applied to a Node by adding a Reference to the AddIn instance.
There are no restrictions for AddIn ObjectTypes and there is no special supertype for AddIns. To identify instances as an AddIn, the HasAddIn Reference or a subtype shall be used.
The AddIn ObjectType shall include the definition of a default BrowseName using the DefaultInstanceBrowseName Property. Instances of such an AddIn should use this default BrowseName. If an AddIn is instantiated multiple times in the same parent, only one instance can have the default BrowseName.
The definition of an AddIn and its use with a default BrowseName is illustrated in Figure 12.
Figure 12 – Example of AddIn with default BrowseName
As already described, an AddIn can be applied on types and instances. The use on an instance is shown in Figure 13.
Figure 13 – Example of AddIn applied to an instance
Clients can detect the implementation of AddIns by passing the HasAddIn Reference as filter to the Browse Service request. If an AddIn has a default BrowseName, Clients can use the TranslateBrowsePathsToNodeId Service with the default BrowseName to get the NodeId of an AddIn.
In the example in Figure 12 the relative path “MyFeature/MyPropertyM” with the starting node MD002 can be used to request the NodeId of this Property and the relative path “MyFeature/MyMethodO” can be used for the respective Method.