Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Database

Designing Class Libraries for Visual Builders


Designing Class Libraries for Visual Builders

The authors are researchers for IBM. They can be reached at [email protected].


Early object-oriented class libraries were designed for programmers who wrote every line of application code themselves. Today, application programmers use visual builders and wizards to generate much of an application's code. In this environment, programmers tie classes together by interface, with a minimum of handwritten code. Designing a good class library consequently requires addressing the needs of visual programmers as well as those of direct coders. Unfortunately, the requirements of these two groups sometimes diverge.

Luckily, "parts" can address both sets of needs. A part is a class with special characteristics to support visual programming and code generation. Well-designed parts comply with a simple but powerful interface protocol; see Figure 1.

The part interface is composed of three clearly defined programming interface features -- Attributes, Actions, and Events. These features correspond to a natural way of viewing objects: their properties, the behaviors they can perform, and their response to internal changes. This protocol addresses the general format of the programming interfaces, but not the specific implementation of the interface.

The Attribute interface provides access to the properties of a part. The Attribute interface can be used to return the value of a property as an object, set the value of a property, and notify other parts when the value of a property changes. Class designers are not required to supply a complete Attribute interface for a property. For example, a property might be read-only, in which case the part's Attribute interface would not support the ability to set the property's value.

The Action interface provides access to a behavior of a part. Actions represent tasks that the part supports, such as displaying itself or adding an object to a collection of objects. Class designers implement this interface in a part by supplying a public member function or method.

The Event interface provides a means to notify other parts that something has changed within a part. Events can be signaled when changes in state occur, such as when a push button is clicked, window opened, or threshold reached (such as when the balance in a bank account goes negative). Events can also be signaled when the value of a part's property changes (such as when money is deposited into or withdrawn from a bank account). Events appear as broadcast messages to all parts that are registered as being dependent on the occurrence of the event.

Connecting Parts

With visual builder technology, application programmers can connect parts to build larger composite parts or entire applications. IBM's VisualAge C++ builder, for instance, lets you make several kinds of connections. (Some connections are themselves classes derived from classes that implement event notification.)

  • Event-to-action connections start an action when a certain event occurs. The action can have parameters. These parameters are attributes of the connection. An example is connecting the clicked event from a push button to the clear action on an entry field. A special form of this type of connection, attribute- event-to-action connections, starts an action when an attribute changes value. An example is connecting the street attribute event of an address to the enable action on a save push button.
  • Attribute-to-attribute connections link two data values together so that they always stay the same. An example is connecting the street attribute in an address part with the text (contents) attribute in an entry field.
  • Event-to-script connections cause a script to run whenever a certain event occurs. The script is defined in C++, either as a member function attached to the part class or as custom logic attached to the connection class.

Classes into Parts

The major difference between parts and classes is that parts can notify other parts about changes to themselves, triggering other processing. This distinction is lessening as some more advanced classes add this capability (see the Observable design pattern in Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, John Vlissides, and Ralph Johnson. Addison-Wesley, 1995; also see "Patterns and Software Design," by Erich Gamma and Richard Helm, Dr. Dobb's Sourcebook, September/October 1995). Implementing notification in classes is the first key step toward enabling a class for visual programming. The absence of notification limits the kinds of connections that can be made to a class.

Using a sample part from VisualAge C++, Example 1 shows how notification was added to the IAddress class to signal when the value of street was changed. Example 2, on the other hand, shows how notification was added to the Address class to signal when the value of street was changed using a sample part from the VisualAge Java.

Ready-to-Wear versus Tailor-Made

The most significant difference between parts and classes is related more to usage than to design. Visual programmers work better with self-contained, ready-to-use classes as parts. Such a class might have a large number of configuring options, but it doesn't use ancillary classes to perform its function (as far as the visual programmer can see). An example of such a part class is a telephone entry-field class. The class validates text entered against the specified pattern for a phone number. It has built-in support for drag/drop and substring selection. All Attributes, Events, and Actions for this part are reflected in this class (regardless of the other classes it might use internally).

On the other hand, a direct coder is more comfortable with extending the function of a simple class by combining it with other classes using multiple inheritance or, more likely, composition. An example here is a simple entry-field class that can be optionally combined with one class for pattern filtering, one for drag/drop, and one for text selection. In this example, the entry field acts as a view, while the classes providing additional functionality act as controllers.

The class designer can construct a part by preassembling classes using the same techniques direct coders use. Alternatively, the part can be integrated with the builder such that the builder assembles the classes according to a part configuration set by the visual programmer.

Code Generation

A more subtle difference between parts and classes relates to design. The main factors in measuring good traditional class library design are:

  • Ease of coding. Is it easy for the programmer to write code using the class library? Do many classes have to be derived and many methods overridden? Is there unnecessary duplicate code for the programmer to write?
  • Performance and size. Does the resulting application run fast? Is the resulting application suitably small in memory and disk footprint?
  • Robustness. Has the class library code been thoroughly tested to ensure that it does not introduce errors into the resulting application?

With a visual builder added to the equation, class designers worry less about ease of coding, because code for derived classes and overrides is generated. Instead, class designers must worry about the usability of the builder. How much configuration information must the programmer supply in order for the builder to generate code correctly? How easy is it to supply that information? The programmer must also be able to debug, document, and manage the code once it is generated.

Class-library designers can actually use code-generation technology to their advantage. Consider the design of a data class -- one whose primary purpose is to encapsulate data and control access to it. Without using code generation, it is difficult to design such an abstract base data class that provides significant inheritance to classes derived from it.

For example, every concrete data class has at least one accessor function and one mutator function (get and set) for each Attribute, Action, or Event. If the class supports persistence, the designer must write functions to stream attributes in and out. Scripting support might require additional accessor functions. All these accessor functions might take different input arguments; they might return a value or object, depending on the Attribute. Accessor logic might vary greatly. No abstract class design can account for all these situations. However, visual builders can generate code for all cases, given a few bits of information by the programmer. In this respect, visual builders provide better support (to designers as well as programmers) than C++ templates.

Freedom versus Convenience

Visual builders impose some standards on classes to ensure that the generated code works correctly. Class libraries designed for use with a visual builder must adhere to these standards in order for the builder to use them. Some of these standards limit the design of a class, at least the part exposed to the visual builder.

In strongly typed languages like Java and C++, builders have a difficult time (without also being compilers) of ensuring that the code generated to connect two attributes will compile correctly. To help the builders, actions must support a larger variety of argument types for a given function, by means of overloading. This also ensures that the builder can match up return types and argument types. In C++, this even includes accepting arguments of type AClass and type AClass*; it might be trivial for a human being to dereference the input argument, but for some builders, it is not.

Without default constructors, visual builders cannot always generate the correct code. Again, this is because no visual builder is as intelligent as a human being. An experienced programmer can often (but not always) find a harmless constructor to call instead of a default one. This constructor may take arguments that can be given dummy or innocuous values. For example, a GUI frame window part may insist on at least a parent window. Experienced programmers might know that the system desktop window can be used if no other parent is known. It is always better for the class designer to predefine a default value, which means that the class can support a default constructor.

Parts must support certain operators, member functions, and patterns of arguments on those member functions, especially for basic tasks such as positioning, copying, or connecting parts. A direct coder can always read the manual and find some way to accomplish the task. However, consistency and coverage in the member functions supported improve usability even for direct coders.

Some standards that parts must follow result in added functionality essentially for free. A builder can protect visual programmers from name changes designers might make in later releases. The names of Attributes, Events, and Actions as seen by the visual programmer can be mapped to the actual member function names of the part. This second level of indirection is resolved at code generation time, so there is no performance impact on the resulting code. By default, the names are the same. If there is, for example, some future change to the class-library function-naming standards, code can be regenerated to the new interfaces without impacting the visual programmer's implementation.

Builders can give every multiargument member function a more flexible syntax without extra effort by the class designer. Some visual builders enable member function arguments to be specified in any order and any combination desired. Class designers do not have to write an overload for every possible ordering and combination of the arguments. The builder rearranges the arguments and supplies defaults to fit the existing overload. This is resolved at code-generation time, so there is no impact on the resulting code.

A Matter of Degree

Many design principles are similar for both builder-oriented and direct-use class libraries, differing only in the degree to which they must be applied. All class designers should have the goal of reducing complexity in the library structure: reducing the number of classes that must be used and member functions that must be overridden or called to accomplish some task. In direct-use class libraries, this relates mainly to the learning curve. In builder-oriented class libraries, this also relates to the amount of screen real estate. The complexity of a builder work environment is strongly affected by the number of objects on the work surface (the screen). Usually, the upper limit here is even lower than the one imposed by a learning curve.

This limit on interface complexity also extends to the number of connections between parts on the screen. This corresponds to the number of member functions that are called within a block of code. The upper limit for builder connections is much lower than the upper limit on the number of member function calls a direct developer can juggle mentally while editing code. Builders use various layering techniques to reduce the number of connections the user must deal with visually at any given moment. Component architectures, where a single object encapsulates and visually hides a group of subobjects and the connections between them, might also help. It is certainly easier to mentally deal with a modest number of connections when they are portrayed visually as opposed to a series of possibly nested member function calls as seen in a simple editor. Visual builders have a real challenge to make more complex logic just as easy to deal with visually.

Conclusion

Although there are many principles in common between classes and parts, there are significant differences that class-library designers should take into account when creating parts to be used by a visual builder. For instance:

  • Change classes to parts by implementing event notification.
  • Create parts that are ready to use.
  • Follow the standards (default and copy constructors) required or recommended by the visual builder.
  • Provide common Actions or Attributes in the part to reduce the number of connections. Test and use parts with the visual builder to ensure that the number of necessary connections has been minimized.
  • Make parts easy to use by providing default parameters and supporting multiple data types as input to Actions and Attributes.

DDJ


Copyright © 1998, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.