Рефакторинг оператора Switch в моем контроллере - PullRequest
4 голосов
/ 19 июля 2011

В настоящее время я работаю над приложением MVC.NET 3;Недавно я посещал курс «Дяди Боба» Мартина, который вдохновил меня (опозорил меня?) Серьезно взглянуть на мою текущую практику разработки, особенно мои привычки рефакторинга.

Итак: ряд моих маршрутов соответствуютto:

{controller} / {action} / {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
        }    
    }
}

Есть кто-нибудьуспешно применил рефакторинг "заменить переключатель полиморфизмом" к коду вроде этого?Это даже хорошая идея?Было бы здорово услышать ваш опыт такого рефакторинга.

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 19 июля 2011

То, как я на это смотрю, это действие контроллера требует специального результата действия:

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);
}

Контроллер не должен заботиться о том, как сериализовать данные. Это не его ответственность. Контроллер не должен делать никаких сантехнических работ, как это. Он должен сосредоточиться на получении моделей доменов, отображении их для просмотра моделей и передаче этих моделей просмотра для просмотра результатов.

3 голосов
/ 19 июля 2011

Если вы хотите «заменить переключатель на полиморфизм» в этом случае, вы можете создать три перегруженных метода 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)
    {
    }

Как только вы дойдете до этой точки, вы можете продолжить рефакторинг, чтобы получить повторение из вашего контроллера.

...