Interfaces cannot be instantiated, but they can be used as the data type to define an object reference data element, such as in a DEFINE VARIABLE statement or a DEFINE PARAMETER statement. This data element can then be assigned to hold an object reference to an instance of a class that implements the interface. Multiple classes can implement the same interface, which allows the classes to be treated in a common manner. An object reference to an interface can then be used to call these common methods, even though the underlying object might be of different classes. This is similar to having multiple classes inheriting from the same super class (with the exception that an interface itself provides no method implementation). Thus, an object reference to a super class can also be used to call the methods that are defined in the super class, even though the underlying object might be of different subclasses with varying method implementations.
The following example shows a simple interface definition, which is modified from the sample acme.myObjs.Interfaces.IBusObj interface with an additional Name property:
INTERFACE acme.myObjs.Interfaces.IBusObj:
METHOD PUBLIC VOID printObj ( ). METHOD PUBLIC VOID printObj (INPUT pcCopies AS INTEGER).
METHOD PUBLIC VOID logObj (INPUT pcFilename AS CHARACTER).
DEFINE PUBLIC PROPERTY Name AS CHARACTER NO-UNDO
GET.
SET.
END INTERFACE.
Note that this interface declares two overloadings of the printObj( ) method.
The following fragment from the acme.myObjs.CustObj sample class shows how it might implement this interface, extended with the additional Name property:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.
CLASS acme.myObjs.CustObj INHERITS CommonObj
IMPLEMENTS IBusObj:
...
/* Must implement methods defined in the IBusObj interface */ . . . /* First version of printObj prints a single copy of a report */ METHOD PUBLIC VOID printObj( ): OUTPUT TO PRINTER. DISPLAY dtTimestamp. FOR EACH ttCustomer: DISPLAY ttCustomer. END. OUTPUT CLOSE. PublishOutputGenerated("One copy of report sent to printer"). END METHOD.
/* Second version of printObj takes an integer parameter representing the
number of copies to print. */
METHOD PUBLIC VOID printObj (INPUT piCopies AS INTEGER):
DEFINE VARIABLE iCnt AS INTEGER NO-UNDO.
OUTPUT TO PRINTER.
IF piCopies <> 0 THEN
DO iCnt = 1 TO ABS(piCopies):
DISPLAY dtTimestamp.
FOR EACH ttCustomer:
DISPLAY ttCustomer.
END.
END.
OUTPUT CLOSE.
PublishOutputGenerated(STRING(piCopies)
+ " copies of report sent to printer").
END METHOD.
/* Method to log customer information */ METHOD PUBLIC VOID logObj (INPUT pcFilename AS CHARACTER): OUTPUT TO VALUE(pcFilename). DISPLAY dtTimestamp. FOR EACH ttCustomer: DISPLAY ttCustomer. END. OUTPUT CLOSE. PublishOutputGenerated("One copy of report sent to " + pcFilename + " file"). END METHOD.
DEFINE PUBLIC PROPERTY Name AS CHARACTER NO-UNDO
GET():
MESSAGE "Name property GET accessor" VIEW-AS ALERT-BOX.
RETURN Name.
END GET.
SET(INPUT cValue AS CHARACTER):
MESSAGE "Name property SET accessor: value" cValue VIEW-AS ALERT-BOX.
Name = cValue.
END SET.
...
END CLASS.
Note that while a property interface declaration may include a GET and SET accessor, or a GET accessor, or a SET accessor, you cannot force the property to not have a particular accessor in an implementing class. However, you can force the accessor to be missing when an instance of the class is used through an interface reference. You can do this by omitting the accessor in the property interface definition. Even though the accessor might be implemented in the class property, when used through an interface reference it will appear that the accessor implementation does not exist.