Defines a user-defined interface. An interface defined with this statement represents a user-defined data type that defines a set of method, property, and event prototypes for methods, properties, and events that can be implemented by one or more classes. Any class that implements the interface must support all the methods, properties, and events whose prototypes are defined in the interface or any interface from which this interface inherits member prototypes.
Note that you cannot specify "Progress" as the first component of the package name for any ABL user-defined interface. For example,
"Progress.Inventory.IUpdateInv" is an invalid type name for a user-defined interface and results in a compiler error.
INHERITS super-interface-name [ , super-interface-name ]
Also note that if more than one occurrence of a super interface type or member prototype appears in the interface inheritance hierarchy, it is treated as a single occurrence. However,
interface-type-name (the current interface definition type name) can never appear as any
super-interface-name, and can never be inherited by any interface specified by a
super-interface-name. In other words, there can be no cycles (recursive inheritance) in an interface inheritance hierarchy. Otherwise, ABL raises a compiler error.
[ { temp-table | dataset } ... ]
[ method-prototypes ]
[ property-prototypes ]
[ event-prototypes ]
END [ INTERFACE ].
|
Specifies one or more temp-table or ProDataSet object definitions used as parameters by one or more methods declared in this interface. You must specify these object definitions before any method prototypes. The AVM does not allocate memory for these object definitions. You cannot specify an access mode for these object definitions. These object definitions cannot be inherited from a super interface; they are private to the interface in which they are defined.
Declares one or more property prototypes in the interface. A property prototype declares a property of a class without implementing its GET or SET accessors (that is, without specifying the property’s logic). You must specify a property prototype with a PUBLIC access mode. The property prototype must include either a GET and SET accessor, or a GET accessor, or a SET accessor. Although the property declaration cannot have accessor implementations, the property when implemented in a class may include an accessor implementation.
The following samples include two different class definitions that provide similar functionality, but in distinctly different ways. Each class implements the same interface and both classes define a ProDataSet data member (
dsHighCustData) used to retrieve
Customer and related
Invoice table data for a single
Customer record from the
sports2000 database. However, each class selects the
Customer record using a different and functionally distinct algorithm provided in its own implementation of the same interface method prototype.
1.
|
r-ICustObjImpl.cls — Defines the r-ICustObjImpl class, which retrieves data from the single Customer and related Invoice records that contain the highest balance value represented by the Customer.Balance value. This functionality is almost identical to what is provided by the r-CustObj.cls sample class file that is fully described in the Examples section of the CLASS statement reference entry. (The main differences from the r-ICustObjImpl class are that the r-CustObj class does not implement an interface type and it is defined as FINAL.)
|
2.
|
r-ICustObjImpl2.cls — Defines the r-ICustObjImpl2 class, which also retrieves data from a single Customer and related Invoice records. However, this class retrieves data for the Customer whose related Invoice records contain the highest Invoice balance represented by the sum of their Invoice.Amount values.
|
INTERFACE r-ICustObj:
/* Property prototypes to return basic values for the Customer
identified with the highest balance in the database */
DEFINE PUBLIC PROPERTY HighCustBalance AS DECIMAL NO-UNDO
GET.
SET.
DEFINE PUBLIC PROPERTY HighCustNum AS INTEGER NO-UNDO
GET.
SET.
/* Event prototype to notify about Customers with Invoices */
DEFINE PUBLIC EVENT CustHasInvoices
SIGNATURE VOID ( piCustNum AS INTEGER ).
/* Temp-tables for the ProDataSet parameter */
DEFINE TEMP-TABLE ttCust NO-UNDO LIKE Customer.
DEFINE TEMP-TABLE ttInv NO-UNDO LIKE Invoice.
/* ProDataSet parameter for passing a single Customer with the highest
balance along with its related Invoices */
DEFINE DATASET dsHighCustData FOR ttCust, ttInv
DATA-RELATION FOR ttCust, ttInv
RELATION-FIELDS (ttCust.CustNum, ttInv.CustNum).
/* Method prototype to get the current high Customer balance data */
METHOD PUBLIC VOID GetHighCustomerData
( OUTPUT DATASET dsHighCustData BIND ).
/* Method prototype to set (or reset) the current high Customer data */
METHOD PUBLIC VOID SetHighCustomerData ( ).
END INTERFACE.
|
The implementations of the SetHighCustomerData( ) method populate the ProDataSet with selected fields from
Customer and
Invoice records, where the selected
Customer also has related invoices. Each implementation of
SetHighCustomerData( ) also sets the two implemented properties (
HighCustBalance and
HighCustNum) to appropriate values for the selected
Customer, and publishes the implemented class event (
CustHasInvoices) for each
Customer record it encounters with related
Invoice records. Each class defines additional data members to support its instance of the ProDataSet, and also must implement the
GetHighCustomerData( ) method (according to the interface) to pass the ProDataSet as a by-reference output parameter.
Following is the interface implementation provided by the r-ICustObjImpl sample class. Note that the property implementations add initial values, but rely on default behavior for the accessors. The class also fully defines the ProDataSet to be passed as a by-reference method output parameter.
CLASS r-ICustObjImpl IMPLEMENTS r-ICustObj:
/* Public properties to return basic values for a customer with the
highest balance */
DEFINE PUBLIC PROPERTY HighCustBalance AS DECIMAL INITIAL 0.0 NO-UNDO
GET.
SET.
DEFINE PUBLIC PROPERTY HighCustNum AS INTEGER INITIAL ? NO-UNDO
GET.
SET.
/* Public event to notify about Customers with Invoices */
DEFINE PUBLIC EVENT CustHasInvoices
SIGNATURE VOID ( piCustNum AS INTEGER ).
/* Private handle variable for the high customer ProDataSet */
DEFINE PRIVATE VARIABLE hHighCustData AS HANDLE NO-UNDO.
/* Private temp-tables for the high customer ProDataSet */
DEFINE PRIVATE TEMP-TABLE ttCust NO-UNDO LIKE Customer.
DEFINE PRIVATE TEMP-TABLE ttInv NO-UNDO LIKE Invoice.
/* Private ProDataSet for a single customer with the highest
balance and its invoices */
DEFINE PRIVATE DATASET dsHighCustData FOR ttCust, ttInv
DATA-RELATION FOR ttCust, ttInv
RELATION-FIELDS (ttCust.CustNum, ttInv.CustNum).
/* Private query and data sources for the ProDataSet */
DEFINE PRIVATE QUERY qCust FOR Customer.
DEFINE PRIVATE DATA-SOURCE srcCust FOR QUERY qCust.
DEFINE PRIVATE DATA-SOURCE srcInv FOR Invoice.
/* Constructor to initialize handles and attach data sources */
CONSTRUCTOR r-ICustObjImpl ( ):
hHighCustData = DATASET dsHighCustData:HANDLE.
BUFFER ttCust:ATTACH-DATA-SOURCE( DATA-SOURCE srcCust:HANDLE ).
BUFFER ttInv:ATTACH-DATA-SOURCE( DATA-SOURCE srcInv:HANDLE ).
END CONSTRUCTOR.
|
/* Public method to get the current high customer data */
METHOD PUBLIC VOID GetHighCustomerData
( OUTPUT DATASET dsHighCustData BIND ):
END METHOD.
/* Public method to set (or reset) the current high customer data */
METHOD PUBLIC VOID SetHighCustomerData ( ):
hHighCustData:EMPTY-DATASET( ).
FOR EACH Customer: /* Find Customer with highest balance */
FIND FIRST Invoice WHERE Invoice.CustNum = Customer.CustNum NO-ERROR.
IF AVAILABLE Invoice THEN DO:
IF Customer.Balance > HighCustBalance THEN
ASSIGN HighCustBalance = Customer.Balance
HighCustNum = Customer.CustNum.
CustHasInvoices:Publish( Customer.CustNum ).
END.
END.
QUERY qCust:QUERY-PREPARE("FOR EACH Customer "
+ "WHERE Customer.CustNum = " + STRING(HighCustNum) ).
hHighCustData:FILL( ).
END METHOD.
END CLASS.
|
The bold code inside the SetHighCustomerData( ) method shows the difference in implementation from the same method implemented by the following
r-ICustObjImpl2 sample class. Here, it relies on the stored value of the
Customer.Balance field to determine each
Customer balance and assigns the
HighCustBalance and
HighCustNum property values accordingly.
The following r-ICustObjProc.p sample procedure shows an application of the
r-ICustObjImpl class, which responds to the
CustHasInvoices class event and displays the contents of the
dsHighCustCata ProDataSet. Note that it defines a reference-only instance of the ProDataSet as required by the class and its interface. (This application is identical to the
r-CustObjProc.p sample procedure described in the Examples section of the
CLASS statement, but which instantiates the
r-CustObj sample class instead.)
CLASS r-ICustObjImpl2 IMPLEMENTS r-ICustObj:
/* Public properties to return basic values for a customer with the
highest balance */
DEFINE PUBLIC PROPERTY HighCustBalance AS DECIMAL INITIAL 0.0 NO-UNDO
GET.
SET.
DEFINE PUBLIC PROPERTY HighCustNum AS INTEGER INITIAL ? NO-UNDO
GET.
SET.
/* Public event to notify about Customers with Invoices */
DEFINE PUBLIC EVENT CustHasInvoices
SIGNATURE VOID ( piCustNum AS INTEGER ).
/* Private handle variable for the high customer ProDataSet */
DEFINE PRIVATE VARIABLE hHighCustData AS HANDLE NO-UNDO.
/* Private temp-tables for the high customer ProDataSet */
DEFINE PRIVATE TEMP-TABLE ttCust NO-UNDO LIKE Customer.
DEFINE PRIVATE TEMP-TABLE ttInv NO-UNDO LIKE Invoice.
/* Private ProDataSet for a single customer with the highest
balance and its invoices */
DEFINE PRIVATE DATASET dsHighCustData FOR ttCust, ttInv
DATA-RELATION FOR ttCust, ttInv
RELATION-FIELDS (ttCust.CustNum, ttInv.CustNum).
/* Private query and data sources for the ProDataSet */
DEFINE PRIVATE QUERY qCust FOR Customer.
DEFINE PRIVATE DATA-SOURCE srcCust FOR QUERY qCust.
DEFINE PRIVATE DATA-SOURCE srcInv FOR Invoice.
/* Constructor to initialize handles and attach data sources */
CONSTRUCTOR r-ICustObjImpl2 ( ):
hHighCustData = DATASET dsHighCustData:HANDLE.
BUFFER ttCust:ATTACH-DATA-SOURCE( DATA-SOURCE srcCust:HANDLE ).
BUFFER ttInv:ATTACH-DATA-SOURCE( DATA-SOURCE srcInv:HANDLE ).
END CONSTRUCTOR.
|
/* Public method to get the current high customer data */
METHOD PUBLIC VOID GetHighCustomerData
( OUTPUT DATASET dsHighCustData BIND ):
END METHOD.
/* Public method to set (or reset) the current high customer data */
METHOD PUBLIC VOID SetHighCustomerData ( ):
DEFINE VARIABLE dBalance AS DECIMAL NO-UNDO.
hHighCustData:EMPTY-DATASET( ).
/* Find Customer with highest total Invoice balance */
FOR EACH Customer:
ASSIGN dBalance = 0.0.
FOR EACH Invoice WHERE Invoice.CustNum = Customer.CustNum:
ASSIGN dBalance = dBalance + Invoice.Amount.
END.
IF dBalance > HighCustBalance THEN
ASSIGN HighCustBalance = dBalance
HighCustNum = Customer.CustNum.
IF dBalance > 0.0 THEN
CustHasInvoices:Publish( Customer.CustNum ).
END.
QUERY qCust:QUERY-PREPARE("FOR EACH Customer "
+ "WHERE Customer.CustNum = " + STRING(HighCustNum) ).
hHighCustData:FILL( ).
END METHOD.
END CLASS.
|
The bold code inside the SetHighCustomerData( ) method shows the difference in implementation from the same method implemented by the previous
r-ICustObjImpl sample class. Here, it calculates the
Customer balance from the total of
Invoice.Amount values in its related
Invoice records and assigns the
HighCustBalance and
HighCustNum property values accordingly.
The following r-ICustObjProc2.p sample procedure shows an application of the
r-ICustObjImpl2 class, which is very similar to the previous procedure,
r-ICustObjProc.p. The differences include displaying both the stored
Customer.Balance value and the
Invoice.Amount total for the selected
Customer record, as well as some cosmetic changes to the display. Otherwise, the application is identical.
|
A class definition (.cls) file can contain only one interface definition that is optionally preceded by one or more USING statements. The complete interface definition must begin with the INTERFACE statement and end with the END statement, and the INTERFACE statement must be the first compileable statement after any USING statements in the file. A class definition file containing an interface definition cannot also contain a class definition.
|
|
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, it will appear, when used through an interface reference, that the accessor implementation does not exist.
|