When I was first taught Object Oriented principles, it was drilled into me that when using objects in a "hasA" relationship (or any similar situations where a helper object encapsulates a discrete smaller purpose in a bigger system), the owned class should not have awareness of it's greater environment, so, for example:
- Class Deck has a Card[], each Card has no upward access to Deck
- Class GameBoard has GamePiece, each GamePiece has no upward access towards the board
This has held well and true for a while, but I've finally had a problem where I'm strongly tempted to break from this.
In an application where there's user defined "commands" that are parsed from input, and run, it made relative sense to define Class Command and Class Conditional, which each have subclasses for each of the many possible Command types the user can define.
Added context This is a Roleplaying utility, so each command relates to an operation done on the "Character" object, or messing with the generators rules. So AddStat(WIL,5) increments that value accordingly. Commands shouldn't need access to the greater generator to run themselves, but they'd need at least access to the object their represented command modifies. So for most purposes, the character is the "environment" the command would be acting on.
Makes sense, seems at first glance to help things. But there's a missing link when a lot of these classes can only do very basic input validation without a greater context, not to mention the fact that without more "aware" objects, every part of the code dealing with them would need to do that main ifelseif branch to first figure out which command it's dealing with...
The design thing I'm not sure where to go with here is as follows (this is not yet coded because of the amount of changes it'd take to adapt one of these divergent solutions)
- Command remains "dumb" with no Character/Environment awareness. Conditional is allowed a resolve(Character obj) method, which lets it be passed enough awareness to return a meaningful true/false. This means Command remains a relatively simple basic syntax validator, and body code elsewhere does the heavy lifting for running
- As before, except Command also gains it's own resolve(Character obj) method, and each subclass contains the code necessary to execute the command
- As before, except we outright create Command objects with a reference to the Character
I'm not really sure where to go on this one... While technically there's already some code organization gained by the simplest option, it feels the readability of the application would benefit from Option 2/Option 3, even if the encapsulation purism suffers.
Which route is the way to go here? Or am I off the mark completely?