Dar*_*rio 9 c# design-patterns
我目前正在编写一个小C#库来简化实现很少的物理模拟/实验.
主要组件是在SimulationForm
内部运行定时器循环并从用户隐藏样板代码.实验本身将通过三种方法定义:
Init()
(初始化一切)Render(Graphics g)
(渲染当前模拟状态)Move(double dt)
(移动实验dt
几秒钟)我只是想知道让用户实现这些功能的更好选择是什么:
1)由继承表单覆盖的虚拟方法
protected virtual void Init() {}
...
Run Code Online (Sandbox Code Playgroud)
要么
2)事件
public event EventHandler<MoveSimulationEventArgs> Move = ...
...
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,方法不应该是抽象的.其实,还有更和他们都不具有实施.由于许多模拟不需要它们,因此将它们放在外面通常很方便.
关于这是一个"正常形式"的酷事是你可以写
partial class frmMyExperiment : SimulationForm {
}
Run Code Online (Sandbox Code Playgroud)
并且您完全能够与设计器和所有继承的控件和设置/属性进行交互.我不想通过采用完全不同的方法来失去这些功能.
LBu*_*kin 15
有趣的是,我不得不在最近工作的设计中做出类似的选择.一种方法并不严格优于另一种方法.
在你的例子中,没有额外的信息,我可能会选择虚拟方法 - 特别是因为我的直觉让我相信你会使用继承来模拟不同类型的实验,而你不需要拥有多个订阅者的能力(作为事件)允许).
以下是关于在这些模式之间进行选择的一些一般性观察:
活动很棒:
事件的最大问题是管理订阅者的生命周期可能会变得棘手,并且当订阅者订阅的时间超过必要时间时,您可能会引入泄漏甚至功能缺陷.第二个最大的问题是允许多个订阅者可以创建一个令人困惑的实现,其中各个订阅者互相踩踏 - 或者表现出顺序依赖性.
虚拟方法运行良好:
虚方法的最大问题是您可以轻松地将脆弱的基类问题引入到您的实现中.虚方法本质上是与派生类的契约,您必须清楚地记录它们,以便继承者可以提供有意义的实现.
虚方法的第二大问题是它可以引入深度或广泛的继承树,以便定制在特定情况下如何自定义类的行为.这可能没问题,但如果is-a
问题域中没有明确的关系,我通常会尝试避免继承.
您可以考虑使用另一种解决方案:策略模式.让您的类支持对象(或委托)的分配,以定义Render,Init,Move等应该如何表现.您的基类可以提供默认实现,但允许外部使用者更改行为.虽然与事件类似,但优点是您可以将值返回给调用代码,并且您只能强制执行一个订阅者.
决定一点帮助:
您想通知其他(多个)对象吗?然后使用事件.
你想让不同的实现成为可能/使用多态吗?然后使用虚拟/抽象方法.
在某些情况下,即使是两种方式组合也是一个很好的解决方案.