hcOPF Designtime Strategy

One of the great things IMHO about hcOPF is the design-time binding.  This feature requires you to install a design-time package into the IDE containing the MetaData for your objects.

The hcUIObjectBinder component uses the ThcUIBindingItems specified by the developer to create the appropriate mediator class at run-time and bind the specified attribute (by name) to the specified control (by name).  If you name your controls consistently it would even be possible to add automatic design-time binding by inferring the mediator from the type of control, and matching the name of the control and the attribute.  That feature isn’t available yet, but after configuring the bindings for 30+ controls on a form you can bet I have it planned.

My current project has grown to the point where the objects contain lots of code other than that used at design-time.  Initially I have used some conditional directives to limit the units implicitly imported into the object design-time package.  This has become increasingly difficult as things have grown and have added complications during the compile cycle.  If I’ve built the design-time package recently, then some of the DCUs are built with the conditional directives, so I either re-compile the entire main project, or change the Unit Output Directory for the design-time package to a separate directory (which is what I did).

To make it easier to keep fleshing out the objects, I have considered 2 different approaches:

1) Using Include files containing all the common code used by both the design-time and run-time objects.

2) Creating the base business objects for design-time use and concrete objects descending from them for run-time use.

Neither approach is ideal.

Include files break up the code so much it’s harder to navigate and make sure changes in one file don’t prevent compilation.  Too bad Delphi doesn’t support partial classes.  If it was just the object metadata it would be one thing, but the code for child lists has to be included so they can also be bound at design-time.  Using include files makes it easier to generate class definitions from the database, but I already have a utility that generates my entire unit so I have a good starting point for a business object.

Likewise, inheritance breaks up the class so reading it and understanding the whole run-time object can be more challenging.  This is typical of OOP design though.

What approach would you use and why?

7 Responses to “hcOPF Designtime Strategy”

  1. Dave Says:

    Include files are ok, as long as there aren’t many of them. A handful at most.

  2. Larry Hengen Says:

    There would be a minimum of 2 include files for each domain object assuming they had no children for design-time binding. One for the interface section to define properties for indexed attribute access such as:

    property Description :ThcAttribute Index 7 read GetAttribute;

    Then another include file for the implementation section containing the Register class procedure and the calls to register and unregister the class in the initialization and finalization sections respectively.

  3. Maxim Says:

    Proxy pattern?
    Completely different classes representing domain classes for designtime.
    If class factory is used to create objects it event can have a parameter indicating a state of the system: run or design time resulting in different set of objects created.

  4. Larry Hengen Says:

    Using inheritance works, but has two major drawbacks::

    1) If your object contains children such as child lists that need to be bound at design-time, then you must create abstract versions of those lists. The descendant object must create concrete child list instances and then cast all references to be able to call descendant methods. This is very ugly, although doable.

    2) The ObjectRegistry has no concept of inheritance. If you register a design-time class, say TClientAbstract and at run-time attempt to use a concrete descendant TClient, the framework will complain that TClient has not been registered. You need to register both classes even though they have the same metadata.

  5. Larry Hengen Says:

    One of the downsides to using Include files is that Code Completion and Code Parameters don’t work any more. At least in Delphi 7. It would be nice if the versions of Delphi that support regions would automatically convert an $include directive to a region and allow the code to be edited as if it actually existed in that unit. This would have the added benefit that Code Completion and Code Parameters should then work.

  6. Jeroen Pluimers Says:

    I’ve done a bit (non-designtime) experimentation with code generation based on a DBMS. Here I follow a two-step process:
    - generate abstract and concrete classes the first time
    - generate abstract classes from the second time on

    I considered include files, but they don’t play well in Delphi; all kinds of IDE support that does not work, or does not work well (recompile on changed include files, refactoring across include files, etc).

    –jeroen

  7. Larry Hengen Says:

    @Jeroen,

    Thanks for the comment. So far I have tried a mix of using inheritance, and include files. I found because of 2) in my previous comment that inheritance didn’t work as well as using include files. Child lists are also problematic. Fortunately, 2) can be resolved, so I will likely adopt the approach you’ve suggested.

    I have put in a QC report (87746) that might alleviate the IDE problems with Include files. Please vote for it if you think it’s a good solution.

Leave a Reply