PreviousNextIndex

INTERFACE statement

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.

You cannot instantiate an interface as an object. You can only use it to define the specified interface for a class (which you can instantiate) that implements the interface.

Note: This statement is applicable only when used in a class definition (.cls) file. For more information, see the Notes section in this reference entry.
Syntax

INTERFACE interface-type-name : 
interface-body 

interface-type-name
interface-body
temp-table | dataset
method-prototypes
property-prototypes
event-prototypes
END [ INTERFACE ]
Examples

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.

Thus, each of the following sample class files implements the r-ICustObj interface type defined in the class definition file, r-ICustObj.cls and provides the following functionality:

  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.

Following is the interface definition provided by the sample r-ICustObj.cls file.

r-ICustObj.cls
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.

r-ICustObjImpl.cls
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.)

r-ICustObjProc.p
DEFINE TEMP-TABLE ttCust NO-UNDO REFERENCE-ONLY LIKE Customer. 
DEFINE TEMP-TABLE ttInv  NO-UNDO REFERENCE-ONLY LIKE Invoice. 
DEFINE DATASET dsHighCustData REFERENCE-ONLY FOR ttCust, ttInv 
  DATA-RELATION FOR ttCust, ttInv  
    RELATION-FIELDS (ttCust.CustNum, ttInv.CustNum). 
       
DEFINE VARIABLE rObj AS CLASS r-ICustObjImpl NO-UNDO. 
rObj = NEW r-ICustObjImpl( ) NO-ERROR. 
rObj:CustHasInvoices:Subscribe( "CustHasInvoices_Handler" ) NO-ERROR. 
MESSAGE "High Customer Number:" rObj:HighCustNum SKIP  
        "High Customer Balance:" rObj:HighCustBalance VIEW-AS ALERT-BOX. 
         
rObj:SetHighCustomerData( ) NO-ERROR. 
MESSAGE "High Customer Number:" rObj:HighCustNum SKIP 
        "High Customer Balance:" rObj:HighCustBalance VIEW-AS ALERT-BOX. 
rObj:GetHighCustomerData( OUTPUT DATASET dsHighCustData BIND ) NO-ERROR. 
CURRENT-WINDOW:WIDTH-CHARS = 90. 
FOR EACH ttCust, EACH ttInv BREAK BY ttInv.CustNum:  
  DISPLAY ttCust.CustNum WHEN FIRST-OF(ttInv.CustNum) 
          ttCust.Name WHEN FIRST-OF(ttInv.CustNum) 
          ttCust.Balance WHEN FIRST-OF(ttInv.CustNum)  
          ttInv.InvoiceNum ttInv.Amount SKIP  
    WITH FRAME A WIDTH 90 DOWN  
         TITLE "Customer with highest stored balance" NO-ERROR. 
END. 
PROCEDURE CustHasInvoices_Handler: 
  DEFINE INPUT PARAMETER pCustNum AS INTEGER. 
     
  FIND FIRST Customer WHERE Customer.CustNum = pCustNum NO-ERROR. 
  IF AVAILABLE Customer THEN  
    MESSAGE "Customer" Customer.CustNum ('"' + Customer.Name + '"')   
            "has a stored balance of" Customer.Balance  
            "and also has Invoices."  
            VIEW-AS ALERT-BOX. 
       
END PROCEDURE. 

Following is the interface implementation provided by the r-ICustObjImpl2 sample class. This implementation is identical to r-ICustObjImpl except for the SetHighCustomerData( ) method.

r-ICustObjImpl2.cls
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.

r-ICustObjProc2.p
DEFINE TEMP-TABLE ttCust NO-UNDO REFERENCE-ONLY LIKE Customer. 
DEFINE TEMP-TABLE ttInv  NO-UNDO REFERENCE-ONLY LIKE Invoice. 
DEFINE DATASET dsHighCustData REFERENCE-ONLY FOR ttCust, ttInv 
  DATA-RELATION FOR ttCust, ttInv  
    RELATION-FIELDS (ttCust.CustNum, ttInv.CustNum). 
       
DEFINE VARIABLE rObj AS CLASS r-ICustObjImpl2 NO-UNDO. 
rObj = NEW r-ICustObjImpl2( ) NO-ERROR. 
rObj:CustHasInvoices:Subscribe( "CustHasInvoices_Handler" ) NO-ERROR. 
MESSAGE "High Customer Number:" rObj:HighCustNum SKIP  
        "High Invoice Balance:" rObj:HighCustBalance VIEW-AS ALERT-BOX. 
         
rObj:SetHighCustomerData( ) NO-ERROR. 
MESSAGE "High Customer Number:" rObj:HighCustNum SKIP 
        "High Invoice Balance:" rObj:HighCustBalance VIEW-AS ALERT-BOX. 
rObj:GetHighCustomerData( OUTPUT DATASET dsHighCustData BIND ) NO-ERROR. 
CURRENT-WINDOW:WIDTH-CHARS = 100. 
FOR EACH ttCust, EACH ttInv BREAK BY ttInv.CustNum:  
  DISPLAY ttCust.CustNum WHEN FIRST-OF(ttInv.CustNum) 
            COLUMN-LABEL "Customer!Number" 
          ttCust.Name WHEN FIRST-OF(ttInv.CustNum) 
          ttCust.Balance WHEN FIRST-OF(ttInv.CustNum)  
            COLUMN-LABEL "Stored!Balance" 
          ttInv.InvoiceNum COLUMN-LABEL "Invoice!Number" 
          ttInv.Amount (SUB-TOTAL BY ttInv.CustNum) SKIP  
    WITH FRAME A WIDTH 100 DOWN  
         TITLE "Customer with highest total Invoice balance" NO-ERROR. 
END. 
PROCEDURE CustHasInvoices_Handler: 
  DEFINE INPUT PARAMETER pCustNum AS INTEGER. 
     
  FIND FIRST Customer WHERE Customer.CustNum = pCustNum NO-ERROR. 
  IF AVAILABLE Customer THEN  
    MESSAGE "Customer" Customer.CustNum ('"' + Customer.Name + '"')   
            "has a stored balance of" Customer.Balance  
            "and also has Invoices."  
            VIEW-AS ALERT-BOX. 
       
END PROCEDURE. 

Notes
See also

Class-based object reference, CLASS statement, DEFINE DATASET statement, DEFINE EVENT statement, DEFINE PROPERTY statement, DEFINE TEMP-TABLE statement, METHOD statement, Type-name syntax, USING statement


OpenEdge Release 10.2B
Copyright © 2009 Progress Software Corporation
PreviousNextIndex