Я пытаюсь придумать соглашение об именах, которое точно передает то, что происходит внутри класса, который я разрабатываю. Во втором примечании я пытаюсь выбрать между двумя почти эквивалентными пользовательскими API.
Вот ситуация:
Я создаю научное приложение, в котором одна из центральных структур данных имеет три фазы: 1) накопление, 2) анализ и 3) выполнение запроса.
В моем случае это структура пространственного моделирования, внутренне использующая KDTree для разделения набора точек в трехмерном пространстве. Каждая точка описывает один или несколько атрибутов окружающей среды с определенным уровнем достоверности относительно самого измерения.
После добавления (потенциально большого количества) измерений в коллекцию владелец объекта запросит его, чтобы получить интерполированное измерение в новой точке данных где-то в соответствующем поле.
API будет выглядеть примерно так (код на Java, но это не очень важно; для ясности код разделен на три раздела):
// SECTION 1:
// Create the aggregation object, and get the zillion objects to insert...
ContinuousScalarField field = new ContinuousScalarField();
Collection<Measurement> measurements = getMeasurementsFromSomewhere();
// SECTION 2:
// Add all of the zillion objects to the aggregation object...
// Each measurement contains its xyz location, the quantity being measured,
// and a numeric value for the measurement. For example, something like
// "68 degrees F, plus or minus 0.5, at point 1.23, 2.34, 3.45"
foreach (Measurement m : measurements) {
field.add(m);
}
// SECTION 3:
// Now the user wants to ask the model questions about the interpolated
// state of the model. For example, "what's the interpolated temperature
// at point (3, 4, 5)
Point3d p = new Point3d(3, 4, 5);
Measurement result = field.interpolateAt(p);
Для моей конкретной проблемной области будет возможно выполнить небольшую дополнительную работу (разделив точки на сбалансированное KDTree) во время РАЗДЕЛА 2.
И будет небольшая работа (выполнение некоторых линейных интерполяций), которая может произойти во время РАЗДЕЛА 3.
Но есть огромный объем работы (создание оценщика плотности ядра и выполнение быстрого преобразования Гаусса с использованием рядов Тейлора и функций Эрмита, но это совершенно не относится к делу), которые должны быть выполнены между разделами 2 и 3.
Иногда в прошлом я просто использовал ленивую оценку для построения структур данных (в данном случае это было бы при первом вызове метода "interpolateAt"), но затем, если пользователь вызывает " field.add () "метод снова, я должен полностью отбросить эти структуры данных и начать все заново.
В других проектах я потребовал, чтобы пользователь явно вызвал метод "object.flip ()", чтобы переключиться из "режима добавления" в "режим запроса". Приятно то, что в таком дизайне пользователь лучше контролирует точный момент, когда начинаются сложные вычисления. Но для потребителя API может быть неприятно отслеживать текущий режим объекта. И, кроме того, в стандартном случае использования вызывающая сторона никогда не добавляет другое значение в коллекцию после начала выдачи запросов; агрегация данных почти всегда полностью предшествует подготовке запроса.
Как вы, ребята, справились с разработкой такой структуры данных?
Предпочитаете ли вы, чтобы объект лениво выполнял тяжелый анализ, отбрасывая промежуточные структуры данных при поступлении новых данных в коллекцию? Или вы требуете, чтобы программист явно перевернул структуру данных из режима добавления в режим запроса?
А вам известно какое-либо соглашение об именах для таких объектов? Есть ли образец, о котором я не думаю?
В режиме редактирования:
Кажется, что есть некоторая путаница и любопытство в отношении класса, который я использовал в своем примере с именем "ContinuousScalarField".
Вы можете получить довольно хорошее представление о том, о чем я говорю, прочитав эти страницы википедии:
Допустим, вы хотели создать топографическую карту (это не моя точная проблема, но концептуально она очень похожа). Таким образом, вы проводите тысячи измерений высоты на площади в одну квадратную милю, но у вашего съемочного оборудования есть предел погрешности плюс-минус 10 метров по высоте.
После того как вы собрали все точки данных, вы вводите их в модель, которая не только интерполирует значения, но и учитывает погрешность каждого измерения.
Чтобы нарисовать топографическую карту, вы запрашиваете у модели высоту каждой точки, в которой хотите нарисовать пиксель.
Что касается вопроса о том, должен ли один класс отвечать за добавление и обработку запросов, я не уверен на 100%, но я так думаю.
Вот аналогичный пример: классы HashMap и TreeMap позволяют добавлять и запрашивать объекты. Нет отдельных интерфейсов для добавления и запроса.
Оба класса также похожи на мой пример, потому что внутренние структуры данных должны поддерживаться на постоянной основе для поддержки механизма запросов. Класс HashMap должен периодически выделять новую память, повторно хэшировать все объекты и перемещать объекты из старой памяти в новую память. TreeMap должен постоянно поддерживать баланс дерева, используя структуру данных красно-черного дерева.
Единственная разница в том, что мой класс будет работать оптимально, если он сможет выполнить все свои вычисления, как только узнает, что набор данных закрыт.