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

Kat*_*ath 2 c# switch-statement

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

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

    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));
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

谢谢阅读.

Yan*_*rtz 6

你有很好的直觉.

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

你应该继续你的想法,有一个基本的抽象类BaseTool,使用不同的OnXXX方法实现为nops(只返回,所以你只需要指定行为,如果你的工具知道如何对方法采取行动),并且每个工具继承自BaseTool并通过覆盖相关方法来实现自己的行为.

所以你的方法最终成为了

public void OnEditorViewMouseDown(Point mousePos)
{
  currentTool.OnEditorViewMouseDown(mousePos);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 是的,这绝对是我的想法.这也被称为rjohnston的回答所述的战略模式 (2认同)

rjo*_*ton 5

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