LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Two OO options but is either right?

I posted something similar on LAVA recently, but this is slightly different, and since different people frequent different forums, I thought I'd throw it out over here. Sorry to those of you that have read something similar already.

 

I have some classes that have a "message to send" in their data. This message is defined at runtime startup based on a config file. Now, some of these messages have private data that needs to be updated at run time, and some have data that will not change throughout the lifetime of the object. For example, one message may be "open relay." The relay being opened will never change (unless the config change). But then there are other messages such as "Set Analog Line To <x> volts" and the value of x may change based on other conditions.

 

So I have come up with two options: 1) have a base message class and put the method for "update value" in the base class. Children that need it can override it (dynamic dispatch), children that don't, won't and they will just call the parent implementation which does nothing. But, now I have something in the base class that doesn't apply to all children, so the question arises should it be there in the first place? Or, I can only put the method in the "updatable" classes (thus keeping them out of the base class) and use a cast then call the method directly, thus scrapping dynamic dispatching (shown below).  Does either of these make more sense than the other? Or does the fact that I'm having to do this point to a design flaw?

 

 

0 Kudos
Message 1 of 11
(1,485 Views)

You say you have two options but only detail one.

 

Put the "update method" in a child class and have staggered inheritance.

 

Having a method in the parent class which is not needed by a lot of siblings is bad design IMHO.  You want a base class, base class & Value and then inherit from the right one for whatever type of message you require.

 

Shane.

0 Kudos
Message 2 of 11
(1,456 Views)

First option looks fine up to this moment:

But, now I have something in the base class that doesn't apply to all children


The question here is: if there is something like this in the base class, should it really be the base class to all other? Maybe this is the slight flaw in the design which is the root of the problem? First step to resolve this would be creating one more "higher" class, which would define the common interface for the others (in this case we can call it just "Updatable") and then derive from it current base class (something like "UpdatableWithOtherStuff") and other classes (without the "Stuff").

 

Second option (with casting) is counter-OO, so I wouldn't go this way. Unless, of course, there are no other solutions. Casting is not bad, just harder to maintain.

0 Kudos
Message 3 of 11
(1,455 Views)

@PiDi wrote:

 

Second option (with casting) is counter-OO, so I wouldn't go this way. Unless, of course, there are no other solutions. Casting is not bad, just harder to maintain.


I completely agree, but because I don't know until run time which messages will be configured, they all need to inherit from the same base class so they can all be injected on the same wire, based on the user's configuration. My idea was when I get incoming data, loop through all the messages and if they were an "updatedable" message, then update the with the correct incoming data. I don't see how to do this without the cast (without having the method defined in the parent class), since they will all have to inherit from the same parent.

0 Kudos
Message 4 of 11
(1,438 Views)

I think I don't understand your problem fully, but what about first solution I've proposed? To create one more "superclass" above all, which would act only as interface - i.e. have empty Update() method.

 

If you could show some code example (how-it-might-be-done-and-where-it-gets-broken) or class diagram, that would give much more field for discussion 😉

0 Kudos
Message 5 of 11
(1,429 Views)

You are really not limited in the ancestory of your classes.  Ok, your parent's method doesn't apply to all of its children classes.  So?  Make a child class with that method and then attach all children with that option to THAT class.  That would make more sense because it sounds like this method is common amongst a subset of your children classes.  Sounds like you need grandparents, parents, and children.

0 Kudos
Message 6 of 11
(1,422 Views)

@PiDi wrote:

I think I don't understand your problem fully, but what about first solution I've proposed? To create one more "superclass" above all, which would act only as interface - i.e. have empty Update() method.

 

If you could show some code example (how-it-might-be-done-and-where-it-gets-broken) or class diagram, that would give much more field for discussion 😉


I will do this tonight; I was just being lazy 😉

0 Kudos
Message 7 of 11
(1,413 Views)

I experienced the similar problem but haven't found a good solution to it. Yes, another higher class which has Update() method is good. But what if their children must different terminals? Inheriting a VI requires to use the same terminals. I wonder how others are handling this.

TailOfGon
Certified LabVIEW Architect 2013
0 Kudos
Message 8 of 11
(1,408 Views)

Personally I preload my messages with a data object which then gets called upon whenever the time is right.

 

Requiring different connector panes for Dynamic dispatch OOP functions is bad design.

 

Shane.

0 Kudos
Message 9 of 11
(1,385 Views)

Threw together this example quickly. Disclaimer: Coding style guidelines were not followed. This shows my first idea, where the update would be in the base class, but it doesn't make sense because that method doesn't apply to the other child class. However, it does allow DD to handle things. I think my other method, the one pictured in my first message, is pretty clear. My attachment is LV2012

0 Kudos
Message 10 of 11
(1,349 Views)