Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based and Procedure Objects : Summary comparison of classes and procedures

Summary comparison of classes and procedures

The following table compares the application implemented by the sample classes (see Sample classes) with the equivalent application implemented by comparative procedures (see Comparative procedures). The code numbers in the table match the commented numbers in the code for both classes and procedures.
Table 9. Comparing sample classes to similar sample procedures
Code No.
Sample classes
Comparative procedures
The acme.myObjs.CustObj class inherits from acme.myObjs.Common.CommonObj. (Note that CustObj can reference its super class as CommonObj because a USING statement specifies its package.)
CustProc.p defines a handle variable and runs CommonProc.p persistently, setting that handle. CustProc.p then uses ADD-SUPER-PROCEDURE( ) to define CommonProc.p as its super procedure.
All the setup for acme.myObjs.CustObj takes place in its constructor.
All the setup for CustProc.p takes place in the main block of the procedure.
To establish an object reference to acme.myObjs.Common.MsgObj, the MessageHandler( ) method is implemented and invoked inside the acme.myObjs.CustObj class. The method is defined as abstract in the super class (CommonObj) and returns an instance of acme.myObjs.Common.MsgObj.
To establish a handle to MsgProc.p, the MessageHandler user-defined function, which returns a handle to MsgProc.p is first defined as a prototype IN SUPER. The function is defined in the super procedure, CommonProc.p. It is later invoked CustProc.p and returns a handle to MsgProc.p.
The updateTimestamp( ) method is invoked on an instance of the abstract acme.myObjs.Common.CommonObj, where it is implemented, and also inherited by acme.myObjs.CustObj. This method is also called on a passed CommonObj reference from InitializeDate( ), which is implemented in the acme.myObjs.Common.HelperClass class and called, in turn, from ObjectInfo( ) of the Main class.
The updateTimestamp internal procedure is called directly from Main.p in CustProc.p, and is found in its super procedure, CommonProc.p. The same internal procedure is called directly from NEMain.p in NECustProc.p, and is found in its super procedure, CommonProc.p.
The updateTimestamp( ) method initializes the value of the PROTECTED dtTimestamp data member in acme.myObjs.Common.CommonObj. Because it is an inherited data member, it can be referenced in both the subclass, acme.myObjs.CustObj, and its subclass, acme.myObjs.NECustObj.
The updateTimestamp procedure in CommonProc.p initializes the value of the SHARED variable, dtTimestamp. In order for both CustProc.p and NECustProc.p to use dtTimestamp, they must both define it as NEW SHARED for reference by their own CommonProc.p super procedures. Note that super procedures do not provide data inheritance, requiring the use of either shared variables (as in this case) or internal procedures and user-defined functions to encapsulate and provide access outside the defining context.
When acme.myObjs.CustObj is deleted, the destructor automatically runs and cleans up program resources.
Before deleting the procedure object, the internal procedure CleanUp is called in both Main.p and NEMain.p to clean up resources.
The acme.myObjs.NECustObj class inherits from acme.myObjs.CustObj, which inherits from acme.myObjs.Common.CommonObj, as described in for Code No. 1. This allows the Main class to access all of the methods on NECustObj that it accesses on CustObj, depending on the constructor used to instantiate Main.
NECustProc.p must go through the same process to add CommonProc.p as a super procedure, as did CustProc.p, as described in Code No. 1. In addition, NECustProc.p must also add CustProc.p as a super procedure in order for NEMain.p to access all of the internal procedures in NECustProc.p that Main.p accesses in CustProc.p.
The constructor for acme.myObjs.NECustObj invokes the constructor for acme.myObjs.CustObj using the SUPER statement. If the CustObj constructor took parameters, (which it does not in this case), NECustObj would pass them in this statement.
If CustProc.p took parameters (which it does not in this case), as for any calling procedure, NECustProc.p would then have to pass them when it ran CustProc.p.
The acme.myObjs.NECustObj class overrides the GetCustomerName( ) method in acme.myObjs.CustObj. The override uses the SUPER system reference to invoke the super class implementation of this method.
NECustProc.p defines a separate version of the GetCustomerName internal procedure defined in the super procedure CustProc.p. The NECustProc.p version uses the RUN SUPER statement to invoke the super procedure implementation of this internal procedure.
The Main class defines two (overloaded) constructors, one without parameters that initializes an acme.myObjs.CustObj instance and one that takes, as a parameter, the name of a text file containing E-mail addresses used to initialize an acme.myObjs.NECustObj instance. The driver procedure, Driver.p, instantiates the Main class once for each constructor, followed by an associated call to the Main method, ObjectInfo( ), which drives the reporting for the currently instantiated customer object. Note that ObjectInfo( ) uses reflection to identify the type name of the particular customer object currently referenced by rCustObj. It can then display an alert box indicating the time when it starts initializing reports for the identified customer object.
Main.p and NEMain.p each implement separate procedure mainlines. Main.p instantiates and drives the CustProc.p procedure object and NEMain.p instantiates and drives the NECustProc.p procedure object, which takes as a parameter the name of a text file containing E-mail addresses used to initialize a NECustProc.p object. Because each driver procedures knows the identity of the particular procedure object it is instantiating, it can display a specific alert box to indicate the initialization time of reports for that object.
The acme.myObjs.CustObj class defines two overloadings of the printObj( ) method, one that prints a single copy of a report of data for all customers to the default printer and another that prints the number of copies specified by a parameter. CustObj defines these method overloadings because it implements the interface, acme.myObjs.Interfaces.IBusObj, which specifies them. In addition, the acme.myObjs.NECustObj class overrides this overloaded method to print a report of e-mail addresses for New England customers in a similar manner. The main driver method, ObjectInfo( ), defined in the Main class and called by Driver.p, determines which overloading of printObj( ) to call from its own input parameter.
The CustProc.p procedure defines a single PrintProc internal procedure that prints one copy, or as many copies specified by a parameter, of the report for all customers. The NECustProc.p procedure defines its own version of PrintProc that effectively "overrides" the version in CustProc.p to print the mail address report for New England customers in a similar manner.The printObj( ) method overloadings in the class samples might be more simply implemented like PrintProc in the procedure samples. However, the use of overloading does allow a different distribution of logic in the same decision tree while conserving the method name.
The acme.myObjs.CreditObj class defines a property, CustCreditLimit, that is readable from outside the class hierarchy (PUBLIC), but writable only from the defining class or its subclasses (PROTECTED). In this case, the property is written by the CheckCustCredit( ) method that is defined within the CreditObj class, and is read by the CheckCredit( ) method that is defined within the unrelated acme.myObjs.CustObj class.
CreditProc.p defines a private CustCreditLimit variable and two user-defined functions to access it. The GetCreditLimit function reads the variable value and is publically accessible. The SetCreditLimit function writes the variable value, but is only accessible from within CreditProc.p (PRIVATE) and is called by the internal procedure, CheckCustCredit. The GetCreditLimit function is called by the CheckCredit internal procedure in CustProc.p.
The acme.myObjs.CreditObj class provides error handling for both the CustCreditLimit property and the CheckCustCredit( ) method. The CustCreditLimit property throws an error object initialized with an error string when it is set for a customer whose balance is over their current credit limit. The CheckCustCredit( ) method automatically re-throws the property error object, if thrown, up to its caller, and also throws its own error object initialized with an appropriate error string for an unavailable Customer record. The CheckCredit( ) method in the acme.myObjs.CustObj class responds to both of these error conditions raised by the method.
CreditProc.p provides a similar structured error handling capability for its corresponding user-defined functions and internal procedure, and the CheckCredit internal procedure of CustProc.p responds to these error conditions in a similar manner, as well.
The acme.myObjs.CustObj class defines a PROTECTED temp-table (ttCustomer) that is accessed by its subclass, acme.myObjs.NECustObj. Because of data inheritance, both CustObj and NECustObj directly access the same instance of ttCustomer.
CustProc.p defines a private temp-table (ttCustomer) that it provides to NECustProc.p using one of its internal procedures (GetTT), which passes the temp-table as an OUTPUT parameter. Note that the temp-table parameter is passed using the BIND option to a REFERENCE-ONLY definition of ttCustomer in NECustProc.p. This allows both CustProc.p and NECustProc.p to access the same instance of ttCustomer.
Several methods in the acme.myObjs.CustObj, acme.myObjs.NECustObj, and acme.myObjs.CreditObj classes execute FIND statements with the NO-ERROR option. The choice is made to use traditional error handling for these statements to show its use together with structured error handling.
The CustProc.p, NECustProc.p, and CreditProc.p procedures rely on the same traditional error handling technique to handle their FIND statement results.
The public class event, OutputGenerated, is initially defined as abstract in acme.myObjs.Common.CommonObj, along with the protected PublishOutputGenerated( ) method intended for publishing the event. Both are implemented by the derived class, acme.myObjs.CustObj. Providing PublishOutputGenerated( ) allows not only CustObj, but the derived class, acme.myObjs.NECustObj, to publish the event in their respective versions of the printObj( ) and logObj( ) methods, which generate the application output for each class.
The Main class subscribes a different handler for the OutputGenerated event depending on the class constructor that is running, one of which instantiates CustObj and the other of which instantiates NECustObj, so the event is handled appropriately for the class instance that publishes it.
The sample procedures use an OutputGenerated named event to provide similar behavior. In this case, CustProc.p and NECustProc.p each publish the event from their respective versions of the printProc and logProc internal procedures, which generate the application output.Each of the customer procedure objects, CustProc.p and NECustProc.p, is instantiated by a dedicated driver procedure, Main.p and NEMain.p (respectively), and each driver procedure subscribes its own handler for the OutputGenerated event published by its particular customer procedure object.