Я создаю дерево для разбора текста, поэтому я создал несколько узлов:
abstract class Node { }
class TextNode : Node
{
public readonly string Text;
public TextNode(string text)
{
Text = text;
}
public TextNode(char ch)
{
Text = ch.ToString();
}
}
class VariableNode : Node
{
public readonly string Name;
public VariableNode(string name)
{
Name = name;
}
}
Я собираюсь добавить некоторые "ветвящиеся" узлы довольно скоро (узлы, которые содержат другие узлы).
Мне интересно, как лучше их обработать. Прямо сейчас у меня есть код, который выглядит так:
foreach (var item in nodes)
{
if (item is TextNode)
sb.Append(((TextNode)item).Text);
if (item is VariableNode)
sb.Append(dict[((VariableNode)item).Name]);
}
Что кажется немного неуклюжим и будет только ухудшаться, когда я добавлю к нему.
Должен ли я
- Попробуйте как-то инкапсулировать логику в базовый класс
Node
, чтобы я мог просто использовать DoStuff()
функцию, не заботясь о приведении типов?
- Должен ли я добавить какое-нибудь перечисление для каждого типа узла, чтобы я мог использовать переключатель вместо цикла foreach?
- Что-то еще?
Нужно дать вам немного больше контекста. В приведенном выше примере узлам переменных необходим доступ к dict для визуализации.
Я разбираю шаблон. В шаблоне есть переменные. Имена переменных и их значения хранятся в dict. Во время разбора у меня нет значений (ну, я мог бы, но я хочу иметь возможность повторно визуализировать шаблон с другими значениями), поэтому мне нужно иметь возможность передавать различные дикты в шаблон. Как я настроил, шаблон выполняет рендеринг, узлы ничего не делают. Я полагаю, что я мог бы передать диктант еще на один уровень каждому узлу, чтобы они могли визуализировать себя ...
Чтобы уточнить # 1
// in class Template
public string Render(Dictionary<string, object> dict)
{
var sb = new StringBuilder();
foreach (var item in nodes)
sb.Append(item.Render(dict));
return sb.ToString();
}
interface INode {
string Render(Dictionary<string, object> dict);
}
class TextNode : INode
{
private string _text;
public TextNode(string text)
{
_text = text;
}
public TextNode(char ch)
{
_text = ch.ToString();
}
public string Render(Dictionary<string, object> dict)
{
return _text;
}
}
class VariableNode : INode
{
private string _name;
// TODO: filters...
public VariableNode(string name)
{
_name = name;
}
public string Render(Dictionary<string, object> dict)
{
return dict[_name].ToString();
}
}
Думаю, это тоже не такое уж плохое решение.
Решения на данный момент:
- Используйте перечисление и переключатель
- Создайте словарь типов / действий, чтобы сделать переключатель немного чище
- Полиморфизм (х2)
- Шаблон посетителей (еще не читал)
- Использовать ANTLR - хотя ANTLR будет строить дерево, а затем эта проблема снова будет применяться