在C#中重构大型交换机的建议

我在C#/ Winforms中有一个应用程序,它允许用户在网格上放置对象以创建游戏关卡。 它有几个工具用于放置瓷砖/灯/门/实体等。目前我只使用枚举来存储当前选定的工具,并有一个switch语句来运行每个工具代码。 随着我一直在为应用程序添加更多工具,它开始变得像意大利面一样,有很多重复的代码。

这是我的编辑器类中的鼠标按下function的缩减版本:

public void OnEditorViewMouseDown(Point mousePos) { // Check if the click is out of bounds. if (IsLocationOOB(mousePos)) return; if (CurrentTool == ToolType.GroundTile) { // Allow drags along whole tiles only. m_DragManager.DragType = DragManager.DragTypeEnum.Tile; m_DragManager.StartDrag(mousePos); } else if (CurrentTool == ToolType.WallTile) { // Allow drags along grid edges only. m_DragManager.DragType = DragManager.DragTypeEnum.Edge; m_DragManager.StartDrag(mousePos); } else if (CurrentTool == ToolType.PostTile) { // Allow drags along grid points only. m_DragManager.DragType = DragManager.DragTypeEnum.Point; m_DragManager.StartDrag(mousePos); } else if (CurrentTool == ToolType.AreaLight) { // Allow drags anywhere. ie. not snapped to the grid in some way. m_DragManager.DragType = DragManager.DragTypeEnum.FreeForm; m_DragManager.StartDrag(mousePos); } else if (CurrentTool == ToolType.PointLight) { m_CurrentWorld.AddLight(TranslateToWorldCoords(mousePos)); } else if (CurrentTool == ToolType.PlaceEntity) { m_CurrentWorld.PlaceEntity(TranslateToWorldCoords(mousePos)); } } 

该开关用于其他几个函数(OnMouseMove,OnMouseUp),它看起来像是糟糕的设计(在几个函数中复制了大开关)。 有什么建议以更清洁,更可扩展的方式重构这样的东西? 我目前正在考虑使用一个基础Tool类,并让每个工具都有自己的类来覆盖它使用的函数(OnMouseDown()等)。 这听起来合情合理吗?

谢谢阅读。

你有很好的直觉。

通常,在OOP中,当你有一行if或者很多的开关时,它就会产生很强的代码味道。 使这种气味消失的最好方法是采用多态性。

您应该继续使用您的想法,使用基本抽象类BaseTool,将不同的OnXXX方法实现为nops(只返回,因此您只需指定行为,如果您的工具知道如何对该方法采取行动),并且每个工具inheritance自BaseTool并通过重写相关方法来实现自己的行为。

所以你的方法最终成为了

 public void OnEditorViewMouseDown(Point mousePos) { currentTool.OnEditorViewMouseDown(mousePos); } 

根据您的设计,您还应该考虑将DragManager传递给方法,以免与存在的实例变量绑定。 一个EditorContext(包含DragManager),无需获取“全局”变量就能满足方法所需的所有内容,这将使您的方法在重构时更加自包含且不那么脆弱。 设计本身将取决于责任:谁负责什么。

听起来像是使用策略模式的好地方: http : //www.google.com/search? q = c%23 + strategy +pattern

是的,你应该absolutley有一个基类(或至少是一个接口),它定义了所有工具所需的所有常用方法。 尝试使这段代码工作,它会让你很好地了解如何设计你的类:

 m_DragManager.DragType = CurrentTool.DragType; m_DragManager.StartDrag(mousePos); 

其中“CurrentTool”是基类或接口的实例。

所以基本上,当选择“工具”时,在那时你确定你正在处理哪个派生工具,但从那时起,你只处理基类,并忘记任何枚举或类似的东西来确定当前选择的工具。 合理?

是的, 多态性就是你想要的。 您应该定义抽象基类工具或接口ITool,具体取决于您是否需要向基础添加实现(即,如果所有工具之间存在共同function,则可以使用抽象基类)。

当需要完成某些事情时,您的经理应该使用工具或ITool。 您的工具将实现一个Drag函数,该函数获取所需的信息,并返回它需要返回的内容或执行它需要执行的操作。 或者,您可以在Manager和工具之间实现控制反转,并通过属性注入(Tool.Manager = dragManager)将Manager注入工具,然后让工具使用管理器执行它需要执行的操作。

我不太熟悉C#的语法,但一般来说,你可以使CurrentTool成为一个具有StartDrag方法的对象, EndDrag接受一个DragManager作为参数。 然后,当在视图上按下鼠标时,您只需调用CurrentTool.StartDrag(m_DragManager)

尝试标记枚举。 每个位都是不同的特征,并且允许每个单元更好地堆叠特征。

然后你甚至可以用不同的方法检查每一位。