4

我有几个类有一个名为 Tool 的基类。在表单中,我有一个工具参考,其中包含提到的类的实例之一。当窗体上发生 MouseDown 事件时,我调用当前的工具方法 ex。“CurrentTool.MethodWhenMouseDown()”。

大多数工具都有 3 种方法:

MethodWhenMouseDown()
MethodWhenMouseUp()
MethodWhenMouseMove()

但是一两个班级只有:

MethodWhenMouseDown()

现在哪个更好:

1.Tool 中的三个方法都有,不需要的类调用空方法。

2.实现接口ex。IMouseMoveListener 仅由在 MouseMove 事件发生时需要执行的类实现。这样,如果 MouseMove 事件发生,我们会问:

if(CurrentTool is MouseMoveListener)
{
(CurrentTool as IMouseMoveListener).MethodWhenMouseMove();
}

附加信息:
该程序就像 Paint 女士 - 工具是 Brush、Bucket(不需要 MethodWhenMouseMove 的工具)、LineTool 等。
在我的 PaintForm 中,我有一个抽象基类工具的引用,它存储派生类的实例之一。触发事件的是pictureBox。

您是否考虑过工具订阅的事件?– CodesInChaos

我认为在表单中有一个方法是很好的做法,它将在事件发生后调用,并且该方法正在调用 CurrentTool 的 siutable 方法。前任:

void MouseMoveSubscriber(object sender, MouseEventArgs e)
{
CurrentTool.MethodWhenMouseMove(e);
}

我假设每次更改 CurrentTool 时订阅和取消订阅 CurrentTool 的方法是不好的做法?
我还考虑过在表单中​​引用所有工具,并且每个工具都会订阅该事件,并且不需要取消订阅。我认为最大的缺点是每个工具都需要检查它是否是 CurrentTool。
你怎么想的?感谢您提供的帮助。

4

3 回答 3

2

性能不是问题(当用户点击时,不必要地调用空函数的开销没有意义),所以这实际上是关于编码的易用性和代码的清晰度/复杂性/可维护性。

所以我会尽可能简单。

我会用空实现来实现一个基类,因为它干净简单。它需要派生类中的最少代码来获得所需的结果。这也是有道理的(如果你不覆盖点击调用,你本质上是在说“当鼠标被点击时,我希望什么都不做”)。

下一个选项是为鼠标上/下/单击提供事件,并让派生类订阅这些事件,如果他们愿意的话。使用事件是一种标准模式,但它的缺点是您必须处理丑陋的订阅和取消订阅调用。这样做的好处是,如果您将它们公开,这些事件可以由任何人处理,而不仅仅是派生类。

我会避免使用接口和强制转换——对我来说,这感觉像是一种笨拙的方法——它真正实现的只是将“空函数”方法分割成许多不同的类型,而不是一组简单的 3 个虚拟方法。而不是仅仅调用方法并知道它们会起作用,你必须先做很多类型转换和检查——它看起来很乱。

编辑 由于您在问题中添加了更多内容,因此我重新阅读了它,并且想到了另一种可能性:创建一个基本 Tool 类,该类提供所有派生类都需要覆盖的虚拟 MouseDown 处理程序。所有正常的工具都会由此派生。

一个附加的 DragTool 类可以派生为一个中间类,它添加了特殊的一对拖动工具所需的 MouseMove 和 MouseUp 处理程序。

IE

ToolBase (abstract MouseDown)
  |
  +- ClickTool1
  +- ClickTool2
  +- DragToolBase (abstract MouseMove + MouseUp)
      |
      +- DragTool1
      +- DragTool2

这意味着在您的任何工具中都不会有空的实现。

于 2012-08-31T12:46:57.360 回答
1

在不知道您的情况的情况下,我会结合使用接口和基类:
基类使用空虚拟方法实现所有接口。基类是一个纯粹的便利构造。如果一个工具类想要从基类继承但不需要该方法,它不会覆盖它。

在使用工具的代码中,您将单独使用接口。像这样,其他类可以自由地直接实现您的接口。您无需任何牺牲即可获得最大的灵活性。

var mouseMoveListener = CurrentTool as IMouseMoveListener;
var mouseDownListener = CurrentTool as IMouseDownListener;
// ...

if(mouseMoveListener != null)
    mouseMoveListener.MethodWhenMouseMove();
if(mouseDownListener != null)
    mouseDownListener.MethodWhenMouseDown();

请注意:我as只使用而不是isas.

于 2012-08-31T12:28:58.353 回答
0

这取决于实际情况。但是在您的特定情况下(UI 事件),我认为具有空处理程序(虚拟方法)的基类比许多接口要好。实际上,您所有的工具都将从某些 ToolBase 继承。并且调用代码将更小更简单,无需转换为接口。

于 2012-08-31T12:41:58.213 回答