实施“后备”课程
我有一组类,每个类都需要在某个时候决定它们应该在内部使用两种或三种方法中的哪一种来在外部实现相同的功能。理想情况下,这应该包括回退功能,如果 ApproachA 失败,它会尝试 ApproachB(也许还有方法 C、D 等)。到目前为止,我一直在使用像 if (!success) { ApproachB code }
这样的编码。这样做的问题是,后面的几个方法也需要知道选择了哪种方法,并且所有这些方法都开发了自己的 if (MethodChosen) { } else { }
语句。我真的想用一些不那么笨拙的东西来解决这个问题......除了我考虑过的其他选项似乎都不是那么“实用”。以下是我想到的三种方法:
- 实现一个静态 .Create 方法,该方法决定创建两个派生类中的哪一个,其中这两个类都有一个支持它们的接口。这样做的缺点是,您需要两次编写大量相同的代码,并且它并没有真正创建“后备”,因为它强制所有决策都在 .Create 方法中预先完成。这应该可以工作 9/10 次,但还有另外 1/10 次,我希望仅当主尝试失败时才启动后备。
- 与上面相同,但涉及基类或抽象类,要么作为两者的支持类,要么以主类作为后备的基类。这具有相同的后备缺点,但至少很少或没有重复代码。
使用可以在运行时更改的子类实现正常构造的抽象类:即
public void SomeMethodOrConstructor() { if (某些条件) MyChild = ChildClassA; 别的 MyChild = ChildClassB; } 公共无效执行() { MyChild.Execute(); }
选项 3 的问题是在需要时在两者之间传递数据。由于其中一些方法是对外部对象进行建模,因此这种情况相当频繁。嵌套类会自动与其父类共享数据吗?或者我每次打电话都必须传递所有内容?
我还应该考虑什么吗?
更新:第一类已启动并运行责任链。目前,我选择在方法执行期间不使用策略模式或回退,因为我相信最终可能没有必要。我认为大多数这样的执行回退实际上最好留在自己的类别中,因为游戏计划不会完全改变,只需进行一些小的调整即可。如果事实并非如此,我至少知道我现在需要调查什么。
感谢所有帮助最终解决方案的人!
出于好奇,我的最终解决方案大致如下:
- 创建 Handler 抽象类,与维基百科文章中概述的非常相似,但使用
public abstract Handler GetHandler()
函数,并添加其他抽象方法,例如加载、保存等。 - 为父类实现私有处理程序子类(它们也可能是子类,因为它们只会处理该特定类的事情......也避免了以后的命名问题)。子类都在其构造函数中采用父对象类型的参数,因此它们可以轻松访问父对象的数据。
- 从父类的构造函数中,设置责任链处理程序/后继程序(同样,就像示例一样),然后调用 FirstHandler.GetHandler(this) 并存储结果,以便该类知道要使用哪个处理程序将来使用。
- 大多数处理方法都简单地简化为 Handler.MethodName()。
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()
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用责任链。
这完全符合您需要做的事情。
Use Chain of Responsibility.
This perfectly fits with what you need to do.
我认为您需要
任务
/任务
,特别是ContinueWith(Action)
方法和 4 个属性:IsCanceled
、IsCompleted
、IsFaulted
和结果
。I think you need
Task
/Task<T>
, especiallyContinueWith(Action<Task>)
method and 4 properties:IsCanceled
,IsCompleted
,IsFaulted
andResult
.我可能会在这里使用策略模式。
http://en.wikipedia.org/wiki/Strategy_pattern
你只需要传递delgates而不是全班。如果所有方法都使用相同的信息进行处理,这可能会有所帮助。
I would probably use the strategy pattern here.
http://en.wikipedia.org/wiki/Strategy_pattern
You only need to pass delgates instead of whole classes. If all of the methods use the same information for processing, this might be helpful.