I have a set of classes, each of which need to decide at some point which of two or three approaches they should use internally to implement the same functionality externally. Ideally, this should include fallback functionality, where if ApproachA fails, it falls through to try ApproachB (and perhaps approaches C, D, etc.). Up until now, I've just been using coding like if (!success) { ApproachB code }
. The problem with this is that several later methods also need to be aware of which approach was chosen and all of them develop their own if (MethodChosen) { } else { }
statements as well. I really want to address the issue with something less unwieldy...except none of the other options I've considered seems all that "wieldy". Here are the three approaches I thought of:
- Implement a static .Create method that decides which of two derived classes to create, where the two classes have an Interface backing them. The disadvantage of this is that you're writing a lot of the same code twice, and it's not really creating a "fallback" since it forces all decision-making to be done up front in the .Create method. This should work 9/10 times, but there'll be the other 1/10 times where I want the fallback to kick in only when the primary has tried and failed.
- The same as above, but with a base or abstract class involved, either as a backing class for both, or with the primary as the base class for the fallback. This has the same fallback disadvantage, but at least there's little or no repeated code.
Implement a normally-constructed abstract class with child classes which can be changed at run-time: i.e.
public void SomeMethodOrConstructor() { if (someConditions) MyChild = ChildClassA; else MyChild = ChildClassB; } public void Execute() { MyChild.Execute(); }
The problem with option 3 is passing data between the two when needed. Since some of these methods are modelling outside objects, that'll be fairly frequent. Do nested classes share data with their parent class automatically? Or will I have to pass it all with every call?
Anything else I should consider?
Update: The first class is up and running with the Chain of Responsibility. For now, I've opted not to use the Strategy Pattern or the fallback during method execution, as I believe it may be unnecessary in the end. I think most such execution-fallbacks will actually be better off by staying within their own classes, since there won't be a complete change of gameplan, just a few minor tweaks to deal with. If that turns out not to be the case, I at least know what it is I need to investigate now.
Thanks to everyone who helped with the ultimate solution!
For the curious, my ultimate solution worked roughly like this:
- Create Handler abstract class, pretty much as outlined in the Wikipedia article, but with a
public abstract Handler GetHandler()
function, and adding other abstract methods like Load, Save, etc. - Implement private handler sub-classes for the parent class (they might as well be sub-classes, since they'll only be handling things for that particular class...avoids later naming issues too). The child classes all take a parameter of the parent object's type in their constructor, so they have easy access to the parent's data.
- From the parent class's constructor, setup the Chain of Responsibility handlers/successors (again, just like the example), then call
FirstHandler.GetHandler(this)
and store the result so the class then knows which handler to use in future. - Most handled methods then simply reduce to
Handler.MethodName()
.