Jump to content

Specification by containing a class rather than subclassing


Recommended Posts

Hi all,

I've run across a problem when trying to implement the Specification design pattern. My problem is this, I have a class called "Network Controller" which I am using to handle messages being passed over the network (I use the LabView shared variable to pass messages as clusters of strings). Now I decided that I would like to encapsulate the code for handling the messages in a seperate class "Message Handler" which has a method "handle message". This vi could then be overridden by children of "Message Handler" to deal with specific types of message.

The problem arose when I tried to implement this. I decided that "Network Controller" should have a list of subscribers, and they would subscribe themselves by sending a "subscribe" message. The network controller then takes this message and uses a Factory to create the corresponding child class of "Message Handler" in this case "Subcribe Message Handler" which can then run its "handle" vi to add the subscriber to the list. However I cannot pass the "Network Controller" object to the handle vi without the vi breaking. I get an error message saying "One or more of the inputs to this tunnel or shift register does not originate at the dynamic input front panel terminal". Now I could just use a get function to take all the data from the "Network Controller" and pass it to the vi that way, but that's not really what I want to do. I want to pass the "Network Controller" to the Message Handler's "handle" vi so I can use its methods.

The idea behind this design was so that I could simply add functionality to the "Network Controller" class if I decided in the future to pass different messages across the network, by simply adding another child class of "Message Handler", which the Factory would create given the name of the message. I didn't want to do this by using children of "Network Controller" as that didn't seem to make sense to me. A "Subscribe Message Handler" class is not a type of "Network Controller", but it should be able to provide functionality to the Network Controller.

Any thoughts?

Thanks,

Tom

Link to comment

QUOTE(ibbuntu @ Jan 16 2008, 09:05 AM)

I get an error message saying "One or more of the inputs to this tunnel or shift register does not originate at the dynamic input front panel terminal".

That error is just a wiring error. Your VI has a dynamic dispatch output terminal. All the wire paths that lead to a dynamic dispatch output must originate from the dynamic dispatch input, passing through various nodes along the way, but never just swapping out for a new object.

You have two options:

1) Make the output be just a regular output instead of a dynamic dispatch output. This will lose you one of the nicer functionalities of automatic downcasting, but it does allow you to wire arbitrary sources to the output terminal.

2) Follow the wire coming out of the dynamic dispatch input. You can easily follow it because it has a gray background. If the background disappears or turns red between the input terminal and the output terminal, that's the point that you have a problem. If you post a picture of your block diagram, it'll probably be trivial to identify.

Link to comment

QUOTE(Aristos Queue @ Jan 16 2008, 10:12 PM)

That error is just a wiring error. Your VI has a dynamic dispatch output terminal. All the wire paths that lead to a dynamic dispatch output must originate from the dynamic dispatch input, passing through various nodes along the way, but never just swapping out for a new object.

You have two options:

1) Make the output be just a regular output instead of a dynamic dispatch output. This will lose you one of the nicer functionalities of automatic downcasting, but it does allow you to wire arbitrary sources to the output terminal.

2) Follow the wire coming out of the dynamic dispatch input. You can easily follow it because it has a gray background. If the background disappears or turns red between the input terminal and the output terminal, that's the point that you have a problem. If you post a picture of your block diagram, it'll probably be trivial to identify.

Here is a picture of my block diagram:

handle_messages.png

I have now removed the dynamic inputs. The problem occurred at handle.vi when I passed in the network controller. I assume this solution will work, but it looks ugly to me and I was worried that perhaps there is a problem with my design.

Tom

Link to comment

QUOTE(ibbuntu @ Jan 17 2008, 05:26 AM)

I have now removed the dynamic inputs. The problem occurred at handle.vi when I passed in the network controller. I assume this solution will work, but it looks ugly to me and I was worried that perhaps there is a problem with my design.

Noooooo! It wasn't the dynamic *inputs* that was the problem. It was the dynamic *outputs*. By making the input not be generic, you're going to lose your ability to override the method for specific network controller classes!

Please post the original block diagram that had the error -- I think (from your fixed diagram) I know what the issue was, but I'd like to make sure.

Link to comment

QUOTE(Aristos Queue @ Jan 17 2008, 04:57 PM)

Noooooo! It wasn't the dynamic *inputs* that was the problem. It was the dynamic *outputs*. By making the input not be generic, you're going to lose your ability to override the method for specific network controller classes!

Please post the original block diagram that had the error -- I think (from your fixed diagram) I know what the issue was, but I'd like to make sure.

Don't worry, I intially solved the problem by removing all dynamic inputs, but then later realised exactly what you just pointed out, so I went back to the front panel and made the input dynamic again. However the wires on the block diagram didn't seem to change back to ones with a grey border. So I went back and started again, here is a picture of the original problem:

handle_messages_original.png

and this time I simply removed the dynamic terminal output and left input as it was. This now meant that the connecter panes in its parent VIs were different, so I changed those to only have a dynamic input, and changed my output object to give:

handle_messages_new.png

it appears that unless both the input and output terminals are dynamic dispatch the wire does not have a grey border.

Tom

Link to comment

QUOTE(ibbuntu @ Jan 17 2008, 12:08 PM)

The grey background only shows up when you have dynamic outputs... if you only have dynamic inputs, there's no reason for you to have to know where the dynamic input is running to. That's a UI decision I've thought about changing a few times, but generally it doesn't seem to bother anyone, and I kind of like the knowledge that I don't have any dynamic outputs because the grey background is gone.

And now, let's talk about your problem:

post-5877-1200596456.png?width=400

The grey background can be followed all the way to the "handle.vi" subVI call. That call is, I assume, dynamically dispatching on the top input (the message object). In a dynamic dispatch subVI call, the only terminals that can preserve runtime type are the dynamic dispatch outputs. All the other terminals cannot be guaranteed to preserve runtime type. Therefore the grey background is not preserved on those outputs.

Is the Network Controler object actually modified inside "handle.vi"? If it is NOT modified, then you really don't care about the output, and you could just fork the wire that is the input into handle.vi and wire it to handle.vi and directly to the output FPTerminal. Like this:

post-5877-1200596746.png?width=400

However, if you do modify the value, then you have no choice but to make the output FPTerminal not be dynamic dispatch output. There's no way to preserve the runtime type safety across the subVI call.

Link to comment

QUOTE(Aristos Queue @ Jan 17 2008, 06:58 PM)

Yes I do modify the value of Network Controller. That's the whole point of the design, the Message Handler objects are responsible for containing the code to handle the message, however it may be necessary to alter the Network Controller's state depending on the message. For example I have a "Register" message, which will create a "Register Message handler" in my "load message object" factory vi. Then we call Register Message handler's "handle" vi which calls the Network Controller's "add instrument" vi, and the instrument that sent the register message is added to the Network Controller's list of registered instruments.

Why is it not possible to track the path of the object through the subvi, using some special terminal similar to the dynamic dispatch terminal?

Tom

Link to comment

QUOTE(ibbuntu @ Jan 18 2008, 04:29 AM)

Why is it not possible to track the path of the object through the subvi, using some special terminal similar to the dynamic dispatch terminal?

Because we don't know which subVI will be invoked at the dynamic dispatch call. There's no guarantee that every subVI in the method preserves runtime type across its diagram, and even if every subVI in the method happens to do so, there's nothing that says you won't dynamically load a class into memory that adds a new override of the method that doesn't preserve runtime type. Because dynamic input must be wired to dynamic output, we can guarantee the type is preserved at runtime for those terminals.

We've talked about adding arbitrary terminal mappings to dynamic dispatch VIs -- you'd configure output terminals to be tied to particular input terminals and then your diagram would be broken if it didn't actually fulfill that contract. The problem is that the UI configuration for such a system turns out to be pretty difficult and it's a fairly rare use case as compared to a lot of other features that are being demanded from my team.

Link to comment

QUOTE(Aristos Queue @ Jan 19 2008, 03:11 AM)

Because we don't know which subVI will be invoked at the dynamic dispatch call. There's no guarantee that every subVI in the method preserves runtime type across its diagram, and even if every subVI in the method happens to do so, there's nothing that says you won't dynamically load a class into memory that adds a new override of the method that doesn't preserve runtime type. Because dynamic input must be wired to dynamic output, we can guarantee the type is preserved at runtime for those terminals.

We've talked about adding arbitrary terminal mappings to dynamic dispatch VIs -- you'd configure output terminals to be tied to particular input terminals and then your diagram would be broken if it didn't actually fulfill that contract. The problem is that the UI configuration for such a system turns out to be pretty difficult and it's a fairly rare use case as compared to a lot of other features that are being demanded from my team.

Well thanks very much for your replies, and keep up the good work! We just got Labview 8.5 on our servers yesterday, so I'm looking forward to using the new features.

Tom

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.