Заменить гигантский оператор переключателя чем? - PullRequest
17 голосов
/ 18 марта 2009

У меня есть код, который анализирует некоторые файлы шаблонов и, когда он находит заполнитель, заменяет его значением. Что-то вроде:

<html>
<head>
    <title>%title%</title>
</head>
<body bgcolor="%color%">
...etc.

В коде парсер находит их, вызывает эту функцию:

string getContent(const string& name)
{
    if (name == "title")
        return page->getTitle();
    else if (name == "color")
        return getBodyColor();
    ...etc.
}

, а затем заменяет исходный заполнитель возвращаемым значением.

В действительности, это не фиктивная веб-страница, и может быть много (более 50) различных заполнителей.

Мой код - C ++, но я думаю, что эта проблема существует с любым языком. Я думаю, это больше об алгоритмах и дизайне ОО. Единственная важная вещь - это то, что это должно быть скомпилировано, даже если бы я хотел, у меня не могло быть никакого динамического / eval'd-кода.

Я думаю о реализации шаблона Chain of Responsibility, но не похоже, что это значительно улучшит ситуацию.

ОБНОВЛЕНИЕ: и я также обеспокоен этим комментарием в другой теме. Должен ли я заботиться об этом?

Ответы [ 6 ]

25 голосов
/ 18 марта 2009

Используйте словарь, который отображает имена тегов в обработчик тегов.

4 голосов
/ 18 марта 2009

Вы хотите заменить условный полиморфизм . Грубо:

string getContent(const string& name) {
    myType obj = factory.getObjForName(name);
    obj.doStuff();
}

где doStuff перегружен.

3 голосов
/ 18 марта 2009

Я объединю 3 идеи:

  1. (от Стивена Хьюга): используйте фабричный метод, который дает вам разные классы для каждого селектора.
    • (от Нила Баттерворта): на фабрике используйте словарь, чтобы избавиться от большого switch(){}.
    • (мой): добавьте метод setup() к каждому классу обработчика, который добавляет себя (или новый экземпляр класса) в словарь.

объясняя немного:

  • создает абстрактный класс с static dict и методами для регистрации экземпляра с помощью строки селектора.
  • в каждом подклассе метод setup() регистрируется с помощью суперкласса 'dict
  • фабричный метод - чуть больше, чем словарь, читаемый
3 голосов
/ 18 марта 2009

Рассматривали ли вы XSLT? Это очень хорошо подходит для такого рода вещей. Я разработал систему управления контентом, которая сделала то же самое и обнаружил, что XSLT очень эффективен. Парсер делает большую работу за вас.

ОБНОВЛЕНИЕ: комментарий Стивена поднимает важный вопрос - вы захотите, чтобы ваши шаблоны были действительными XHTML, если вы решите пойти по маршруту XSLT. Кроме того, я бы использовал другой разделитель для ваших токенов замены. Что-то менее вероятно произойдет естественным путем. Я использовал #! PLACEHOLDER #! в моей CMS.

2 голосов
/ 18 марта 2009

Как "Дядя" Боб Мартин упоминал в предыдущем подкасте с Джоэлом и Джеффом , почти все, что вы придумали, по сути будет воспроизводить большой оператор switch.

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

Важно убедиться, что существует только один экземпляр вашего большого оператора switch. Ваш оператор switch или словарь должен определить, какой класс обрабатывает этот тег, а затем последующие определения должны обрабатываться с использованием полиморфизма.

2 голосов
/ 18 марта 2009

Вместо разбора попробуйте просто прочитать шаблон в строку, а затем просто выполнить замену.

fileContents = fileContents.Replace("%title%", page->getTitle());
fileContents = fileContents.Replace("%color%", getBodyColor());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...