Лучший способ спроектировать эту функцию?
-
05-07-2019 - |
Вопрос
У меня есть функция, которая состоит в основном из огромного количества вызовов (более 50) другой функции, которая вставляет данные в массив, причем логика здесь и там диктует различные условия для вставки различных элементов в массив (плюс немного в конце, которая записывает содержимое массива в файл).Мне интересно, нет ли лучшего способа сделать эту функцию;Полагаю, я мог бы начать с логического разделения наборов команд вставки массива на их собственные функции, но мне интересно, могу ли я сделать еще что-нибудь.Есть ли?
Пример:
function buildTable(fileName, data)
local dataToWrite = {}
table.insert(datTWrite, {
Type = "type1",
Key = "someKey",
Value = data.SomethingInteresting
})
--and so on ad nauseum with an occasional but of actual logic to spice things up
dataWriter:open(fileName .. ".bla")
dataWriter:batchWrite(dataToWrite)
dataWriter:close()
end
В этом случае DataWriter является экземпляром предопределенного класса, который обрабатывает процесс записи в файл.
Решение
Хорошей новостью является то, что вы не перешли непосредственно к обычной Lua-пессимизации объединения строк в буфер в цикле для построения вашего вывода.
Я бы написал ваш образец следующим образом:
function buildTable(fileName, data) local t = {} t[#t+1] = { Type = "type1", Key = "someKey", Value = data.SomethingInteresting } --and so on ad nauseum with an occasional but of actual logic to spice things up dataWriter:open(fileName .. ".bla") dataWriter:batchWrite(t) dataWriter:close() end
который имеет небольшое преимущество в том, что не использует длинное имя временной таблицы, подверженное опечаткам, и использует t[#t+1]
идиома для расширения части массива, которая должна быть быстрее, чем вызов table.insert()
.
В противном случае источник любых структурных улучшений будет находиться в части кода "и так далее до тошноты".
- Поищите там общие вычисления и фрагменты, которые можно собрать в локальные функции.
- Помните, что вы можете вкладывать определения функций, поэтому область действия вспомогательных функций может быть ограничена местом, где они используются.
- Поищите слишком умную логику и перепишите их, чтобы они были разумны для тех, кому придется поддерживать ее в следующем году.
- Вики: Шаблоны проектирования Lua
- Вики: Дзен Луа
- Вики: Советы по оптимизации
- Вики: Профилирование Lua - кода
Прежде всего, остерегайтесь преждевременной оптимизации.Возьмите за основу то, что у вас есть сейчас, и используйте это как руководство для поиска узких мест в производительности.
Другие советы
Под "и так далее до тошноты со случайной, но реальной логикой, чтобы оживить ситуацию" я предполагаю, что вы имеете в виду, что у вас есть много блоков, таких как:
table.insert(datTWrite, {
Type = "type1",
Key = "someKey",
Value = data.SomethingInteresting
})
Единственным аспектом этого, который является уникальным для функции, является заполняемая таблица и data
объект.Моей личной "лучшей практикой" было бы перенести все это в отдельную таблицу, например:
local entries = {
{
Type = "type1",
Key = "someKey",
ValueField = "SomethingInteresting",
},
{
Type = "type2",
Key = "someOtherKey",
ValueField = "SomethingElse",
},
-- etc.
}
Эта таблица должна быть либо глобальной, либо находиться в области, находящейся за пределами того места, где определена функция.Теперь вы можете более легко перенастроить записи, не внося никаких изменений в функцию, которая выполняет фактическую работу.Сама функция значительно упрощается за счет перебора записей таким образом:
for i, entry in ipairs(entries) do
table.insert(datTWrite, {
Type = entry.Type,
Key = entry.Key,
Value = data[entry.ValueField]
})
end
Для "случайной" логики каждая запись может иметь необязательную функцию, предоставляющую вам интересную информацию в цикле.Например.:
for i, entry in ipairs(entries) do
if not entry.CheckSomething or entry.CheckSomething() then
table.insert(datTWrite, {
Type = entry.Type,
Key = entry.Key,
Value = data[entry.ValueField]
})
end
end
В качестве альтернативы, вы могли бы даже разрешить отдельным записям в таблице БЫТЬ функциями, если вам нужна дополнительная настраиваемость.Каждая функция ввода возвращала бы таблицу (или нет).
for i, entry in ipairs(entries) do
if type(entry) == "function" then
local newEntry = entry()
if newEntry then
table.insert(datTWrite, newEntry)
end
else
table.insert(datTWrite, {
Type = entry.Type,
Key = entry.Key,
Value = data[entry.ValueField]
})
end
end
Не имея ничего конкретного для продолжения, я бы попробовал исследовать код пахнет и посмотрите, как сравнивается ваша функция.Судя по всему, вам, вероятно, есть чем заняться.Существуют ли блоки похожего / скопированного кода, изолированные другой условной логикой?Вложенные циклы или условные выражения?Это несколько простых отправных точек при попытке разбить большую функцию на части.