06-05-2018 03:37 PM - edited 06-05-2018 03:38 PM
I'm working on creating a HAL for a few environmental test chambers, and I'd like a second opinion on my object structure before I get too far into this.
With these test chambers, some of them are temperature only and some are temp + humidity. Some are connected via serial port and some are connected via Ethernet.
Here's my planned object diagram:
-ThermalChamber.lvclass
Private data: Connection.lvclass
Children:
Chamber123.lvclass (concrete implementation for a specific chamber)
ThermalChamberWithHumidity.lvclass
Children:
ChamberABC.lvclass (concrete implementation for a specific chamber with humidity)
-Connection.lvclass
Children:
RS232.lvclass
TCP_IP.lvclass
Does that layout look generally right? Each chamber has a Connection object that describes its actual connection method (RS232 or TCP/IP) which could later be expanded to GPIB or whatever if need be. ThermalChamber.lvclass could have SetTemperature methods overridden by child classes, and ThermalChamberWithHumidity.lvclass could have SetHumidity methods overridden by child classes.
Does that look about right? Any thoughts on better ways to organize things? I feel like this allows me to expand the classes later on if I need to (for example, I can add ThermalChamberWithVacuum as a child of ThermalChamber).
Any help would be much appreciated. Every time I think I have a handle on class layouts I end up reading some article or hearing a podcast and start second guessing everything I've learned so far 🙂
06-05-2018 05:26 PM
Let's start from the back:
@BertMcMahanAny help would be much appreciated. Every time I think I have a handle on class layouts I end up reading some article or hearing a podcast and start second guessing everything I've learned so far 🙂
Don't do that, don't question your design because you saw some new pattern/technique/template/other design. You'll end up running in circles and not actually doing the job. I'm serious, one of the major things to learn in OO is "good enough is enough" (FizzBuzz Enterprise Edition anyone? 🙂 )
That being said...
@BertMcMahan wrote:
I'm working on creating a HAL for a few environmental test chambers, and I'd like a second opinion on my object structure before I get too far into this.
With these test chambers, some of them are temperature only and some are temp + humidity. Some are connected via serial port and some are connected via Ethernet.
Here's my planned object diagram:
-ThermalChamber.lvclass
Private data: Connection.lvclass
Children:
Chamber123.lvclass (concrete implementation for a specific chamber)
ThermalChamberWithHumidity.lvclass
Children:
ChamberABC.lvclass (concrete implementation for a specific chamber with humidity)
-Connection.lvclass
Children:
RS232.lvclass
TCP_IP.lvclass
Does that layout look generally right? Each chamber has a Connection object that describes its actual connection method (RS232 or TCP/IP) which could later be expanded to GPIB or whatever if need be. ThermalChamber.lvclass could have SetTemperature methods overridden by child classes, and ThermalChamberWithHumidity.lvclass could have SetHumidity methods overridden by child classes.
Does that look about right? Any thoughts on better ways to organize things? I feel like this allows me to expand the classes later on if I need to (for example, I can add ThermalChamberWithVacuum as a child of ThermalChamber).
Connection class is generally good idea, it abstracts away the communication. It might be a better idea to move it from parent class to children. Why would children ask parent for the Connection each and every time it needs something done? Those children looks grown enough, let them handle their own things!
As for "ThermalChambersWithXXX" - it smells a little. What about ChamberWithVacuum*And*Humidity? I'm not giving any definitive advice here, because the design is highly dependent on the context. So I'll just leave this for consideration:
06-05-2018 08:52 PM
I would not worry about the connection class/children. If you do the initialization correctly, VISA handles all of it for you.
06-06-2018 10:48 AM
Thanks for both of your inputs. I appreciate the advice to "just get some work done" and quit worrying so much 🙂 Regarding the two layouts (my original and the alternate one) I'd considered the second layout, but was worried about the unimplemented operations. In reading up on the SOLID principles, I believe that second method violates a couple of them, since ConcreteChamber2 has no knowledge of what "humidity" is. I suppose you could implement methods in the parent class that return errors by default (so you'd get an error if a child didn't override the parent). While I think that'd work, it would only throw errors at runtime, not compile time.
I realize my "ThermalChamberWithXXX" isn't a great solution, which was part of why I'm posting here. I wonder if something like "Environmental Chamber" as a base class with "ProcessController" as members might work?
Anyway, I like that you brought up not being able to use ConcreteChamber if a client implements only ThermalChamberWithHumidity. Still, I'd think any subcomponent that didn't need humidity would only use ThermalChamber, and if (and only if) it did need humidity functions then it'd use ThermalChamberWithHumidity.
I don't know a great way to resolve an issue where I need both humidity AND vacuum; it seems like this is a scenario where multiple inheritance would work, but I think you could do it with a bunch of wrappers. At any case, I don't have any chambers like that right now, so I can at least move forward and just "do the job" with one of the two implementations we're discussing.
Re: crossrulz, that's a good point, but I think there may be some implementation details on read/write that may work a little differently. I'll look into it and see if I can get rid of the class altogether and just leave a VISA reference as a parent data member, since all chambers will have some kind of connection handle.