2009-11-10 3 views
0

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

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

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

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

+0

Несомненно, приложение не требует жесткого кодирования всех возможных арендаторов в инструкции switch? Пожалуйста, уточните, как «арендатор» повлияет на метод Render(). –

+0

Было всего 8 арендаторов, поэтому, когда разработчику необходимо было принять решение арендатора, он перечислил их всех. В коде содержится около десятка таких экземпляров. – Mattio

+0

Какие решения основаны на конкретных арендаторах? И что конкретно означает «тип контента»? –

ответ

1

Я думаю, что даю вам.То, что я хотел бы сделать это:

Создать 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). При необходимости вы можете добавить новый метод к суперклассу и добавить конкретную обработку арендатором нового типа контента в подклассы.

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

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

1

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

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

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

+0

OP упоминает, что он работает на C#. Я отредактировал теги, чтобы подчеркнуть это. –

0

Если возможно, вы можете абстрагироваться от редких различий, возникающих на основе типа содержимого, а затем создать набор Renders для каждого арендатора с вспомогательными объектами на тип содержимого. Это превращает проблему в задачу 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()); 

Тогда рендеринге методы для рендера каждого арендатора могли бы реализовать Template Method Pattern и один раз в некоторое время вызывать некоторые метод на 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(); 
    } 
    ... 
} 

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

Смежные вопросы