One of my readers requested I talk about the design process for the object-oriented Getting Started window.
I'm not suggesting this is a perfect, general design process for OO in LabVIEW, but perhaps some people will find an example helpful.
First, I identified the "nouns" in my system: the links. The Getting Started window uses a web-style UI, and the most important things are the hotspots that take actions.
The links became the objects in my design. Link
became my common ancestor class.
Next, I wrote down (on paper - yes, this was all done before I started writing any code) the "verbs" for my objects. They had two primary actions: initializing their data from an XML file and taking action when the user clicked on them. These became the methods on my class.
Next, I thought about the "kinds" of links I had: some opened web pages, some created VIs, some launched wizards, etc. These became classes that inherited from Link
For each of these child classes, I wrote down all the information they needed in order to perform their work. For example, the Web
link needed to know the URL to open. These became the fields of the class private data.
If there was a field that all the child classes had in common, I thought about whether it was an attribute of all links and (if so) put it in the parent class.
Then I hit a small snag: the Targets ring that appears when you have modules such as Real-time installed.
When looking at the information that the ring items needed, I decided to create a new layer in my class hierarchy. I made Clickable text
, a child of Link
, and made another child of link called Ring item
. Then I redistributed the private data fields accordingly.
This was all pretty straightforward. But then I hit a bigger snag: while designing the child classes of Ring item
, I realized one launched a project wizard. But it was also possible to have a clickable text link that launched a project wizard.
"Where should I put the fields for a project wizard?" I asked myself.
I could duplicate the exact same fields in the Project wizard clickable text class and the Project wizard ring item class. But that's not good. Duplication is almost always a bad sign: that means when you make a change in one place, you have to remember to change the other place as well. Sharing code between the two is better.
I considered putting the fields in the common ancestor class, Link
. But that's not good, either. That would mean that all the other child classes would contain fields that were useless to them. That's inefficient, and also confusing to other engineers who want to modify my VIs later.
Ordinarily with OO design, you want to put common functionality into a common ancestor class. But the class hierarchy I wanted to use didn't allow that in this case. There was no common ancestor unique to the project wizard classes.
Then I realized the design pattern
I wanted: delegation. I created another class (which did not inherit from Link
) which launched a project wizard. Then, rather than have the private data fields in the original two classes, I gave them each a private data member that was an instance of the helper class.
After reviewing my design with another engineer, I was confident I had a good approach and started writing VIs.
Up-front design work isn't a guarantee that you won't need to change your design later (when you get new requirements or think of a better approach), but it does reduce the likelihood. When people don't take the time to design before coding, too often they will want to "stick with what they already wrote" instead of using the design they like better.
Of course, I think this applies to software in general, and not just object-oriented design. "An ounce of prevention is worth a pound of cure." :-)