在我的控制器中重构 Switch 语句

发布于 2024-11-25 11:02:25 字数 621 浏览 4 评论 0原文

我目前正在开发 MVC.NET 3 应用程序;我最近参加了“鲍勃叔叔”马丁的一门课程,这启发了我(让我感到羞耻?)认真审视我当前的开发实践,特别是我的重构习惯。

所以:我的许多路由符合:

{controller}/{action}/{type}

其中 type 通常决定要返回的 ActionResult 的类型,例如:

public class ExportController
{
    public ActionResult Generate(String type, String parameters)
    {
        switch (type)
        {
            case "csv":
            //do something
            case "html":
            //do something else
            case "json":
            //do yet another thing
        }    
    }
}

是否有人成功地将“用多态性替换开关”重构应用于类似的代码这?这是个好主意吗?很高兴听到您在这种重构方面的经验。

提前致谢!

I'm currently working on a MVC.NET 3 application; I recently attended a course by "Uncle Bob" Martin which has inspired me (shamed me?) into taking a hard look at my current development practice, particularly my refactoring habits.

So: a number of my routes conform to:

{controller}/{action}/{type}

Where type typically determines the type of ActionResult to be returned, e.g:

public class ExportController
{
    public ActionResult Generate(String type, String parameters)
    {
        switch (type)
        {
            case "csv":
            //do something
            case "html":
            //do something else
            case "json":
            //do yet another thing
        }    
    }
}

Has anyone successfully applied the "replace switch with polymorhism" refactoring to code like this? Is this even a good idea? Would be great to hear your experiences with this kind of refactoring.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

强辩 2024-12-02 11:02:25

在我看来,这个控制器操作正在尖叫着自定义操作结果:

public class MyActionResult : ActionResult
{
    public object Model { get; private set; }

    public MyActionResult(object model)
    {
        if (model == null)
        {
            throw new ArgumentNullException("Haven't you heard of view models???");
        }
        Model = model;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        // TODO: You could also use the context.HttpContext.Request.ContentType
        // instead of this type route parameter
        var typeValue = context.Controller.ValueProvider.GetValue("type");
        var type = typeValue != null ? typeValue.AttemptedValue : null;
        if (type == null)
        {
            throw new ArgumentNullException("Please specify a type");
        }

        var response = context.HttpContext.Response;
        if (string.Equals("json", type, StringComparison.OrdinalIgnoreCase))
        {
            var serializer = new JavaScriptSerializer();
            response.ContentType = "text/json";
            response.Write(serializer.Serialize(Model));
        }
        else if (string.Equals("xml", type, StringComparison.OrdinalIgnoreCase))
        {
            var serializer = new XmlSerializer(Model.GetType());
            response.ContentType = "text/xml";
            serializer.Serialize(response.Output, Model);
        }
        else if (string.Equals("csv", type, StringComparison.OrdinalIgnoreCase))
        {
            // TODO:
        }
        else
        {
            throw new NotImplementedException(
                string.Format(
                    "Sorry but \"{0}\" is not a supported. Try again later", 
                    type
                )
            );
        }
    }
}

然后:

public ActionResult Generate(string parameters)
{
    MyViewModel model = _repository.GetMeTheModel(parameters);
    return new MyActionResult(model);
}

控制器不应该关心如何序列化数据。那不是他的责任。控制器不应该做这样的管道工作。他应该专注于获取领域模型、将它们映射到视图模型并将这些视图模型传递给视图结果。

The way I am looking at it, this controller action is screaming for a custom action result:

public class MyActionResult : ActionResult
{
    public object Model { get; private set; }

    public MyActionResult(object model)
    {
        if (model == null)
        {
            throw new ArgumentNullException("Haven't you heard of view models???");
        }
        Model = model;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        // TODO: You could also use the context.HttpContext.Request.ContentType
        // instead of this type route parameter
        var typeValue = context.Controller.ValueProvider.GetValue("type");
        var type = typeValue != null ? typeValue.AttemptedValue : null;
        if (type == null)
        {
            throw new ArgumentNullException("Please specify a type");
        }

        var response = context.HttpContext.Response;
        if (string.Equals("json", type, StringComparison.OrdinalIgnoreCase))
        {
            var serializer = new JavaScriptSerializer();
            response.ContentType = "text/json";
            response.Write(serializer.Serialize(Model));
        }
        else if (string.Equals("xml", type, StringComparison.OrdinalIgnoreCase))
        {
            var serializer = new XmlSerializer(Model.GetType());
            response.ContentType = "text/xml";
            serializer.Serialize(response.Output, Model);
        }
        else if (string.Equals("csv", type, StringComparison.OrdinalIgnoreCase))
        {
            // TODO:
        }
        else
        {
            throw new NotImplementedException(
                string.Format(
                    "Sorry but \"{0}\" is not a supported. Try again later", 
                    type
                )
            );
        }
    }
}

and then:

public ActionResult Generate(string parameters)
{
    MyViewModel model = _repository.GetMeTheModel(parameters);
    return new MyActionResult(model);
}

A controller should not care about how to serialize the data. That's not his responsibility. A controller shouldn't be doing any plumbing like this. He should focus on fetching domain models, mapping them to view models and passing those view models to view results.

葵雨 2024-12-02 11:02:25

如果您想在这种情况下“用多态性替换 switch”,您可以创建三个重载的Generate() ActionResult 方法。使用自定义模型绑定,设置 Type 参数一个名为 DataFormat (或其他名称)的强类型枚举。然后您将拥有:

 public ActionResult Generate(DataFormat.CSV, String parameters)
    {
    }

 public ActionResult Generate(DataFormat.HTML, String parameters)
    {
    }

 public ActionResult Generate(DataFormat.JSON, String parameters)
    {
    }

一旦到达这一点,您可以进一步重构以从控制器中获取重复。

If you wanted to "replace switch with polymorphism" in this case, you could create three overloaded Generate() ActionResult methods. Using custom model binding, make the Type parameter a strongly-typed enum called DataFormat (or whatever.) Then you'd have:

 public ActionResult Generate(DataFormat.CSV, String parameters)
    {
    }

 public ActionResult Generate(DataFormat.HTML, String parameters)
    {
    }

 public ActionResult Generate(DataFormat.JSON, String parameters)
    {
    }

Once you get to this point, you can refactor further to get the repetition out of your Controller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文