Рефакторинг двух уровней операторов переключателей - PullRequest
0 голосов
/ 11 ноября 2009

Я унаследовал кодовую базу, которая интенсивно использует операторы switch (C #, FWIW) для управления некоторой логикой. Это многопользовательское веб-приложение, в котором один набор операторов переключения относится к отображению контента, а другой - к ссылкам на функции, по крайней мере, в большинстве случаев.

У меня есть возможность провести рефакторинг, поэтому я беру операторы переключения, связанные с контентом, и планирую создать базовый класс Content с помощью метода Render (), а затем настроить конкретные дочерние элементы для типов, которым необходимо переопределить базовую реализацию.

Но в редких случаях рендеринг HTML основан на типе контента и конкретном клиенте, и я не хочу, чтобы все новые методы Render () имели ту же проблему, с которой я начинал. Есть ли шаблон, который может помочь с такой ситуацией?

Я вижу несколько других похожих вопросов по SO, но я не уверен, как применять ответы здесь.

Ответы [ 3 ]

1 голос
/ 12 ноября 2009

Я думаю, что понимаю тебя. Что бы я сделал, это:

Создайте 1 класс для обработки потока управления рендерингом:

class Renderer
{
    Tenant _tenant;

    void Render(ContentType type)
    {
        switch (type)
        {
            case ContentType.JSON: 
                _tenant.RenderJSON();
                break;
            default:
                _tenant.RenderHTML();
                break;
        }
    }
}

Затем создайте 1 суперкласс для Арендатора:

class Tenant
{
    virtual void RenderJSON() { ... };
    virtual void RenderHTML() { ... };
}

Наконец, создайте подклассы для конкретного арендатора:

class JoeBlow : Tenant
{
    override void RenderJSON() { // joe blow's json };
}

Это должно оставить вас с хорошей моделью:

  • 1 класс на одного арендатора (что приятно, поскольку вы говорите, что поведение меняется на каждого арендатора)
  • 1 суперкласс для определения общего поведения (для всех жильцов)
  • 1 место, где ваш contentType разрешается методом рендеринга.

Добавить новый тип контента очень просто: просто обновите переключатель (1). При необходимости вы можете добавить новый метод в суперкласс и добавить специфичную для арендатора обработку нового типа контента в подклассы.

Добавить нового арендатора тоже легко. Просто подкласс их.

Можно иметь переключатели, но если вы повторяете их, что-то не так, imo.

1 голос
/ 11 ноября 2009

Извините, мои навыки проектирования ООП немного ржавые. Вы можете поблагодарить за это макросы Lisp;]

Может быть, использование двух фабричных классов будет работать?

Конструктор класса Content () принимает переменные $ content_type и $ feature. Затем конструктор возвращает экземпляр подкласса Content (), который содержит свойство, инициализированное для экземпляра подкласса Feature (), сгенерированного фабричным классом Feature (), используя значение $ feature для выбора соответствующего подкласса. Когда вызывается метод render () подкласса Content (), этот метод render () может включать в себя вызов метода внутри фабрики Feature (), который может дополнять или дополнительно обрабатывать данные, сгенерированные методом render (). В тех случаях, когда дальнейшая обработка с помощью методов Feature () не требуется, вы можете просто пропустить эти вызовы.

0 голосов
/ 11 ноября 2009

Если это вообще возможно, вы можете абстрагироваться от редких различий, которые возникают в зависимости от типа контента, а затем создать набор визуализаций для каждого арендатора с вспомогательными объектами для каждого типа контента. Это превращает проблему в проблему n + m вместо n * m. Где n и m - количество пользователей и типы контента соответственно. Тогда вы можете построить рендерер так:

// uses a DefaultContentTypeDelegate
IRenderer tenantADefault = new TenantARenderer();
// specify a specific content type helper object
IRenderer tenantAType1 = new TenantARender(new ContentType1Delegate());

Тогда ваши методы рендеринга для каждого средства визуализации арендатора могут реализовать Шаблон метода шаблона и время от времени вызывать какой-либо метод для contentTypeDelegate.

class TenantARenderer : IRenderer {
    ...
    public render() {
        // do a bunch of tenant A specific stuff
        this.contentTypeDelegate.doSomeContentTypeSpecificStuff();
        // do some more tenant A stuff
        this.contentTypeDelegate.doSomeOtherContentTypeSpecificStuff();
    }
    ...
}

Этот дизайн, конечно, зависит от способности четко абстрагироваться от различий в типах контента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...