LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

"Command Pattern" decouples a command from its data - but exactly how?

Solved!
Go to solution

Hi again folks - Generally Accepted Wisdom keeps telling me that using an LVOOP command pattern "decouples" specific commands from the specific data used to invoke them.  So I've used the ole command-enum-bundled-with-variant-data forever but I need some more smarts for this application.  But I'm just not Getting exactly how the command & data get decoupled.  You have to make a new child command class for each specific command, right?  And the "invoker" still has to be able to understand, for every child command class, what exactly to do when it receives it, right?  So I guess there are Dyno-Dispatch methods for invoking the command, but how does all this help me?  Any insight appreciated, paul

0 Kudos
Message 1 of 15
(2,213 Views)

Have you seen this short explanation: https://labviewwiki.org/wiki/Command_pattern

 

My understanding is that the enum / variant cluster gets replaced like this:

Action to perform: enum ---> child class

Data arguments: variant ---> class data

 

You will have one parent level class with an execute method that all the children must overwrite.

Message 2 of 15
(2,200 Views)

I hadn't seen that, thanks.  So the plethora of "Variant To Data" in the receiving 'invokers' get replaced with class methods that really have a one-to-one correspondence with the command child classes?  I think I really need to read up on the idea of the OOP 'Interface' - I'm guessing that that's what simplifies rather than complicates...

0 Kudos
Message 3 of 15
(2,187 Views)

Interfaces let you implement the same method across a variety of classes without creating a parent/child pairing.  It also inherently allows you to not give a child1 a method child 2 has even if they come from the same parent.

 

Rather than ask about concepts, it may help to understand what you're trying to do more so that understanding how you're considering solving it.  Then, you can get guidance on the problem rather than on whether or not a solution, without a problem, is a good match.

0 Kudos
Message 4 of 15
(2,131 Views)

Ahh good point.  I'll try to be brief.  For this application I'm controlling some controllers via TCP.  Like most I've worked with, one mustn't send them a new command before they've finished processing the previous, and returned an acknowledge message.  Now, for each controller in the system, I have a UI loop and a separate "Communications Agent" loop that handles lower-level things like TCP reads/write, timeouts, retries and ACK/NACK checking.  My UI loop sends messages to/from this separate loop.  I started the project by implementing a state machine that 'holds off' the sending of new commands until the previous is complete, using  'Waiting For Response' flag and a command queue - "if we need to send a new command, and the 'Waiting For Response' is set, enqueue the new command and try to execute it on a future iteration" - that sort of thing.

 

Ahh, but later I realized that having scripted commands would be very advantageous.  So I cobbled something up that sorta kinda worked.  But now I'm running into trouble with it (insert irrelevant sad story here), and I see that I built a band-aid Rube Goldberg smelly contraption that really needs fixing.

 

So I remembered something called the "Command Pattern" from when I took the LVOOP course a while back.  I could encapsulate the command-transaction-state-machine stuff in a 'command object'.  I don't have any experience with class override methods but I'm foolhardy enough to take a swing at them - my feeble understanding is that one can make an ancestor abstract command class with 'override required' property, then make a child class for each specific command required, with an override method.  I might even be able to include command children for different controllers under the same ancestor, if that behooves me.  The issue there would be that each controller model has a unique, mostly mutually exclusive command set, so I have a unique 'command' enum type for each controller.  Then, the usual variant data, with the need to unpack on the receiving end with Variant To Data.  I see where Elijah K. talks about this very thing when he discusses the command pattern, so methinks "hey! this might be just the thing!".

 

But then as I read more about the Command Pattern I suspect that an understanding of OO interfaces seems essential.  It might also help with other tasks as well.  If you've read this far, thanks! paul

0 Kudos
Message 5 of 15
(2,111 Views)

I'm not typically one for the UML Diagram.  But, I think something along these lines would be useful for you.  If you're unfamiliar (and for anyone else reading), these are often used to show your class hierarchy in OOP architectures.  You start at the top with a box that includes the name of the parent class, a list of its methods (include public/private/protected), and a list of its properties (also include public/private/protected).

To help understand what you're wanting to accomplish, I'd start here by ignoring the hierarchy.  Instead, look at overall functional elements.  Each of those elements should be able to process commands and have properties to describe them. 

Don't worry about interfaces, command classes, parents, etc.  As the first step, just design some general functional elements. Once you have those, it'll be easier to see how many of the actions/methods are shared.

As a small example, consider making an application that required traditional checking accounts and savings accounts.  If I were to make the diagram, I'd see they share a number of properties and actions (get balance, deposit, withdrawal, open account, close account... balance, owner, account number, etc).  There would also be some that are unique (interest rate, calculate interest, etc).  When I see how similar many things are, I'd likely make a parent class Banking Account with the shared features and then build up the differences in two children classes.

If this were more advanced, I may find that having a parent is a complete mess.  I'd have to put a parent rather high up to get a range of classes to have the same function.  Rather than do that, the interfaces can bring the actions to each of the children without adding a layer of complexity in the hierarchy.  But, it's something that will be hard to understand until we have that first pass at a rough draft of the functional elements and their required actions/properties.  Once you have that, it's much easier to look at what you're trying to do and start to find the best architecture.

Quick note: "override required" isn't ALWAYS needed to allow for overriding parent methods.  The idea there is you have two common options in the parent class:  create a generic method.  create a method that does nothing but provide the method itself and the connector pane parameters.  If you do the second, you NEED to choose override required or the children methods won't work.  If you have a generic method that will work for most classes (such as the get balance from the accounts example), you don't need to override.  You can opt to override individually rather than rewrite the generic method for each child.

0 Kudos
Message 6 of 15
(2,106 Views)

Much thanks, natasftw. Must digest this. Got some unraveling in my near future!

0 Kudos
Message 7 of 15
(2,086 Views)

Been sneaking up on this in my spare time.  (Really wishing I could work in a group of LV programmers so I could get some mentoring!)  Could it be that I'm finally starting to Get It?  Could y'all do me the favor of looking at this little example and tell me if I'm finally on the Righteous LVOOP Path?  I suppose, now that LV2020 includes Interfaces, I could implement polymorphism in a similar way with them...

 

I looked at the Command Pattern (for issuing commands to dissimilar controllers) but one of my controllers has like 30 different commands, bleh... So maybe this simple poly approach is good enough.

 

Much thanks for your time & patience, paul

Download All
0 Kudos
Message 8 of 15
(2,022 Views)

Hi Paul, you should be able to feed both objects into a single VI and have it format as a string.

0 Kudos
Message 9 of 15
(2,012 Views)

Gregory - that's exactly what I did (I *think* - didn't really show it clearly).  I made a VI for the Abstract Class called "Execute Something.vi" which is an empty, do-nothing shell, set the Abstract Class for 'Descendants must override".  I colored all 3 versions of the execution VI differently just to prove to myself that I've finally Gotten this (it's taken me a while to actually Get this😕).  Here's a snippet that shows the Abstract empty "Execute Something.vi".  So the Abstract version 'adapted to' either the Numeric or String inputs.

 

So ya think I might finally have Gotten it? Much thanks, paul

0 Kudos
Message 10 of 15
(2,008 Views)