LabVIEW Development Best Practices Documents

cancel
Showing results for 
Search instead for 
Did you mean: 

Delegation Pattern

Intent

To have two independent classes share common functionality without putting that functionality into a common parent class.

Motivation

Good object-oriented design requires each class to focus on its assigned task. A class shouldn’t have member VIs unrelated to its task. If you have two classes that have some shared functionality, the usual solution is to create a parent class that both of them inherit from. Sometimes, however, you already have a class hierarchy created and a new feature comes along. The new functionality needs to be added to two existing classes that either do not have a common ancestor or do have a common ancestor but that ancestor is several generations up and not every descendent of that ancestor should have the new functionality. In some languages you might try multiple inheritance. But even in languages that support multiple inheritance, delegation is generally a better solution.

This pattern applies best when you have a dynamic VI inherited from some ancestor and two descendent classes want to override that dynamic VI with exactly the same implementation. Delegation helps you avoid writing the implementation twice, once for each of the two classes.

Implementation

An example of this pattern was made available by Christina Rogers in her refactoring of the Getting Started Window in creation of her Project Wizard class (http://www.eyesonvis.com/blog/2006/08/object-oriented-getting-started-window.htm l). As of LabVIEW 2012, this example is now included in the examples folder shipped with LabVIEW at [LabVIEW Path]\examples\lvoop\navigation ... It was deleted from LabVIEW in LabVIEW 2014 because it was judged to not be a sufficiently accessible piece of code to qualify as a shipping example. You will need to find it from an older source.

The general idea is this: Create a third class that has the new functionality. The new class is frequently something like “Function Helper” or “Function Assistant,” where “Function” is whatever functionality is to be delegated. Give that class all the data fields necessary to carry out the new functionality. Then add that third class as a data member to the two classes that need to share the functionality.

The two descendent classes override the ancestor’s dynamic VI. But they only put in a bit of code necessary to call the exact same method on their data member of the helper class. The actual work is entirely in that method of the helper class. Now there is only a single instance of the code, which makes bug fixing easier. The two descendent classes have delegated the work to a third class – thus the name of this pattern.

You might think, “Why not just have a common subVI that isn’t a member of either class?” The answer is that there may well be some state data associated with the helper object. It may have fields of its own which you would have to add to both of the caller classes and then keep in sync. By making it an object, you fully encapsulate this bit of functionality.

Editorial Comments

[Stephen Mercer] This pattern is not listed explicitly in the Gang of Four text. The idea occurs as an aspect of several other patterns. I think it is useful enough to warrant specific attention.

[David Staab] The goal of this pattern is to have a set of common methods that multiple disparate classes can access. In Java, you have to create a new class and put those methods in there. LV provides lots of options for how to achieve this goal, though, and you don't always have to use a class to provide that common access. I've done delegation for common methods of classes inside the same library (.lvlib), wherein I create a new folder in the library and add the common VIs to that folder. I usually mark the folder Private so only the classes in that library can get to those methods. This is an equally valid approach to achieving delegation without requiring a new class to encapsulate the delegate methods. It comes in very handy when you have objects that don't require constructor VIs yet, and you don't want to have to make a constructor just so you can instantiate a delegate object.

Elijah Kerry
Chief Product Manager, Software Platform
_______________________________________________
Follow my Software Engineering for LabVIEW Blog
Comments
Member JChristensen
Member
Active Participant Elijah_K
Active Participant

Thanks - I fixed it.

Elijah Kerry
Chief Product Manager, Software Platform
_______________________________________________
Follow my Software Engineering for LabVIEW Blog
Member Andreik_ee
Member

Where is the pattern implementation to download?

Member MikaelH Member
Member

This is a good deisgn example ([LabVIEW Path]\examples\lvoop\navigation), but I find the link from a base class to a child class a bit strange :-)

Navigation.png

Member crcarlin
Member

It should be emphasized that this design pattern is about avoiding code duplication, not building interfaces.

For example, when seeing mention of multiple inheritance and reading this passage

The new functionality needs to be added to two existing classes that either do not have a common ancestor or do have a common ancestor but that ancestor is several generations up and not every descendent of that ancestor should have the new functionality.

one might get the impression that this design pattern allows dynamic swapping between the existing classes even though they don't inherit the vi from a common ancestor. It does not.

Or to put it another way, this design pattern ONLY addresses what happens inside the existing classes, and not how anyone else interacts with the existing classes.

Active Participant Lily1979
Active Participant

Hello,

I can't find this exemple in \exemples\lvoop\navigation, anyone can give me this code?

Thanks.

Lily

Proven Zealot
Proven Zealot

I have updated the document with this information:

"It was deleted from LabVIEW in LabVIEW 2014 because it was judged to not be a sufficiently accessible piece of code to qualify as a shipping example. You will need to find it from an older source."

I do not have the older code easily accessible at this time. I'll flag Christina and see if she does.

Knight of NI Knight of NI
Knight of NI

I have LabVIEW 2012 SP1 (32-bit) installed on one of my machines, and the Example is here (I'm looking at the opened Project).  I'd be happy to Zip it up, but don't see any place to "attach" it.  AQ -- can you provide me an e-mail address via Private Messaging for a destination?

Knight of NI Knight of NI
Knight of NI

Hmm.  I tried to add a comment to AQ's comment, but may have forgotten to push "Add Comment".  I do have this example on my LabVIEW 2012 SP1 (32-bit) installation, and will make a .ZIP of it.  I don't see how to attach it, but if AQ will send me a Private Message with instructions (such as an E-mail address to send an attachment), I'll follow through.

Bob Schor

Proven Zealot
Proven Zealot

Christina has a copy and will post it somewhere later today or early tomorrow and provide the link. Thanks for checking, Bob.

Active Participant Christina_R
Active Participant

Uploaded here: https://decibel.ni.com/content/docs/DOC-48806


Christina Rogers
Product Owner, LabVIEW R&D
Active Participant Lily1979
Active Participant

Thanks a lot.

I get it.

Lily

Contributors