C# 中大开关的重构建议 [英] Refactoring advice for big switches in C#

查看:17
本文介绍了C# 中大开关的重构建议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application in C#/Winforms that lets users place objects on a grid to create levels for a game. It has several tools for placing tiles/lights/doors/entities etc. Currently I just use an enum for storing the currently selected tool and have a switch statement to run each tools code. As I've been adding more tools to the application it's starting to get spaghetti like, with lots of duplicated code.

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

Here is a cutdown version of the mouse down function in my editor class:

    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() 等).这听起来合理吗?

The switch is used in several other functions (OnMouseMove, OnMouseUp) and it seems like bad design (big switch copied in several functions). Any advice for refactoring something like this in a cleaner and more extensible way? I'm currently thinking of having a base Tool class and having each tool it's own class that overrides the functions it uses (OnMouseDown() etc.). Does this sound sensible?

感谢阅读.

推荐答案

你的直觉很好.

通常,在 OOP 中,当您有一排 if 或巨大的开关时,这是一种强烈的代码气味.消除这种气味的最佳方法是使用多态性.

Usually, in OOP, when you have rows of if's or humongous switches, it's a strong code smell. The best way to make this smell go away is to go with polymorphism.

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

You should go ahead with your idea, having a base abstract class BaseTool, with the different OnXXX methods implemented as nops (just returns, so you only have to specify the behavior if your tool knows how to act on the method), and have each tool inherit from BaseTool and implement its own behavior by overriding the relevant methods.

所以你的方法最终是

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

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

Depending on your design, you should also consider passing the DragManager to the method, so as not to be tied to instance variables laying around. An EditorContext (containing the DragManager) fitted with everything the method needs without having to fetch "global" variables would make your method more self-contained and less brittle when refactoring. The design itself will depend on the responsability: who is in charge of what.

这篇关于C# 中大开关的重构建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆