Home
What's New
Dev Tools
Services
Feedback
Site Map

PFC Extension Strategies and Techniques

PFC extensions are discussed under the following categories:

Creating an Extra Extension Layer

The first question when extending PFC is whether to leave the default layer structure (i.e. PFC supplied by PowerSoft and PFE used for extensions) or whether additional extension layer(s) are needed.

When there is one major application or a small number of very similar applications, then the standard PFE extension layer will probably suffice. However, when there may be a number of applications that share the framework (particularly different classes of applications), then it makes sense to add an intervening "corporate" layer between the PFC layer and PFE layer. The middle or corporate ancestor layer would include functionality that is common to the entire company while each PFE layer is application-specific. A good discussion of extension strategies is provided in a paper at the PFC Guide Site and also in a paper at the PowerSoft site.

Creating an extension layer has become much easier in PFC6 with the new PFC Library Extender Utility. This utility lets you insert an additional extension layer and, if desired, selectively indicate which objects to include / exclude from the process. An existing extension layer code can be left at the upper layer or optionally moved to the newly inserted middle layer.

If you build a corporate layer, you should strive to keep as much common functionality as possible in the corporate layer. This will encourage maximum re-use which increases the benefit of having a corporate framework. In order to ensure that the corporate layer is as comprehensive as possible, consider the following strategies:

The remainder of the extension discussion assumes there is a single extension layer -- it doesn't differentiate extensions made in the corporate layer vs. the application layer.

Extension Logic: When to Choose Ancestor vs. Service

When you build or extend an "ancestor", don't automatically place all your logic into the ancestor object. If you only have a small number of simple scripts, then it usually makes sense to simply include the logic in the ancestor. However, if you are building a large ancestor, then you should consider how to break it down into several logical components. PFC's Window and DataWindow services gives examples of how logic was broken out into logical services.

The drawbacks of a pure ancestor approach were reviewed in the PFC Architecture discussion.

Refer to the table below for criteria that can be used to help decide whether logic is more appropriately placed in an ancestor or a service.

When to Choose Ancestor vs. Service

Factor When Ancestor Approach is better When Service Approach is better
Usage pattern when a significant majority of descendant objects use the functionality when only a subset of descendant objects use the functionality
Size when the functionality is small and can be contained in a small number of functions when the functionality is large and requires several supporting functions
Invocation when logic is invoked from a standard event (it might include the actual logic or it might invoke service object logic) when logic is always explicitly invoked by the descendant object
Visual aspects when the window/object includes several visual controls required by the descendant while a service object may act upon on visual controls, they rarely contain visual controls of their own.
Outside access   when the functionality may need to be accessed from other languages (e.g. imbedded in an OLE, COM, CORBA component) or if the functionality may need to be rewritten in another language for performance reasons

How to Extend (or Correct) a PFC Object

When extending/correcting PFC logic, you will generally want to place the logic into the appropriate layer: either the PFE layer or the corporate layer. These layers were discussed above. As PowerSoft says, code should never be added or modified in the PFC layer (i.e. PBLs starting with PFC...). If you change any code in these PFC layer PBLs, you will cause yourself serious problems when it comes time to apply maintenance releases or upgrade to a new version (e.g. PFC5 to PFC6).

When writing logic in an extension layer, it is best to try to allow the standard PFC logic to execute and to avoid doing an outright override of PFC logic. There are a few reasons for this:

The following low risk extension methods are preferable (least risky first):

Necessary PFC Overrides

As much as you might like to try to let existing PFC logic execute, it won't always be possible, such as the situations below:

In these situations, you have to override the PFC logic and add this event/function to your "PFC override list" (this is the list that you carefully review with each PFC upgrade).

As a general rule, it is best to copy the PFC function or event into the extension layer. You can then add your logic into the copied PFC routine. Carefully mark each place that you add code or make code changes -- this will make it easier to deal with future PFC upgrades to the "copied" script.

Building Visual Ancestors (or Services)

Approaches to Building Visual Ancestors

You can take two broad approaches to building visual ancestors: paint it or build it as components. In the example, we'll say we want to build an ancestor response window that has one DataWindow and three command buttons: OK, Cancel and Help.

Approach 1: Paint the Visual Ancestor Window

With this approach, you paste actual controls (e.g. u_cb for the command buttons and u_dw for DataWindow) onto your window. Each control is given a name (e.g. cb_OK, cb_Cancel, cb_Help, dw_Detail) and that control name is referred to elsewhere in the ancestor code.

Approach 2: Build the Visual Ancestor with "Components"

With this approach, the ancestor doesn't have any objects prepainted on it. Instead, descendant objects inherit from the ancestor object and "paste on" standard objects that are needed (e.g. they paste on OK button, Cancel button and Help button user object as well as a Detail DataWindow user object). The components pasted on might be generic (e.g. OK button) or they may be specific to the object itself (e.g. the DataWindow user object might apply only to this ancestor window). Standard variables (e.g. icb_OK, icb_Cancel, icb_Help and idw_Detail) are generally declared by the ancestor and initialized by the descendant. The ancestor uses these variables to perform operations on the objects (e.g. disable a command button, insert a row into the DataWindow, etc.)

Avoid Creating too many Visual Ancestor "Flavours"

It may be tempting to create several flavours of ancestor window (e.g. a simple Detail Window with one Detail DataWindow, a ListEdit Window with one editable list DataWindow, a DetailListEdit with one Detail DataWindow and one ListEdit DataWindow, etc.) In creating such ancestors, you might feel you have more control when managing the component controls -- e.g. initiating AcceptTexts, sorts, calls to middle tier logic, etc.

In general, the better solution is to have the descendant load handles for each relevant window control into an ancestor array variable. The ancestor can then loop through this component control array to perform appropriate operations on appropriate controls. PFC 6 now implements such a design for updating purposes (i.e. self updating objects).

With "Self Updating Objects", any descendant can provide PFC with an array of updateable controls on the window (each DataWindow, single line edit, etc.). Then, during save processing, PFC calls special object-level functions for AcceptText, Validation PreSave, Update, PostSave processing for each control. These functions can be written to perform necessary custom operations (e.g. the Update might call a middle tier function for updating) or the default logic can be left.

Writing Visual Ancestor Code

Service or Ancestor

The first question to ask: should you build the logic into the ancestor itself or should logic be separated out into one or more services? See When to Choose Ancestor vs. Service.

Logic Placement for Window Actions

When writing logic associated with clicking command buttons or menu items, try to avoid placing code code into the menu or command button itself. Instead, trigger an event on the window (e.g. ue_OK, ue_Sort, etc.) and then place logic into the user event (or trigger the appropriate service logic from this user event). This approach provides several benefits:

Extending Non-Visual Services

When extending non-visual services (e.g. Conversion, String, INI, etc.), it is usually much easier to avoid conflicting with PFC's logic. Unless there is a bug in the existing service function, you should create a new function (or event) with a name that different from PFC's and then use your function when needed. Using a unique name will avoid PFC upgrade problems and it will avoid affecting other PFC services.


Copyright © Woodger Computing Inc.