Из опыта работы также с научно-исследовательскими разработками с мягкими ограничениями производительности в реальном времени (и иногда с классами жира), я бы предложил НЕ использовать мапперы ИЛИ.В таких ситуациях вам лучше иметь дело с «прикосновением к металлу» и работать непосредственно с наборами результатов JDBC.Это мое предложение для приложений с мягкими ограничениями в реальном времени и огромным количеством элементов данных в пакете.Что еще более важно, если число отдельных классов (не экземпляров классов, а определений классов), которые необходимо сохранить, велико, , и у вас также есть ограничения памяти в ваших спецификациях , вы также захотите избегать ORM, таких как Hibernate..
Возвращаясь к исходному вопросу:
Похоже, у вас есть типичная проблема: 1) отображение нескольких элементов данных в модели ОО и 2) такие несколько элементов данных не отображаютсяхороший способ группировки или сегрегации (и любая попытка группировки имеет тенденцию просто не чувствовать себя правильным.) Иногда модель предметной области не подходит для такой агрегации и обычно предлагает искусственный способ сделать этозаканчивается компромиссами, которые не удовлетворяют всем требованиям и желаниям проектирования.
Что еще хуже, модель ОО обычно требует / ожидает, чтобы все элементы присутствовали в классе как поля класса.Такой класс обычно не имеет поведения, поэтому это просто struct
-подобная конструкция, или data envelope
или data shuttle
.
Но в таких ситуациях возникают следующие вопросы:
Должно ли ваше приложение считывать / записывать все 40, 50+ элементов данных одновременно, всегда? * Должны ли все элементы данных присутствовать всегда? *
Не делаюзнаю специфику вашей проблемной области, но в целом я обнаружил, что нам редко приходится иметь дело со всеми элементами данных одновременно.Это где реляционная модель сияет, потому что вам не нужно запрашивать все строки из таблицы сразу.Вы извлекаете только те, которые вам нужны, как проекции рассматриваемой таблицы / представления.
В ситуации, когда у нас есть потенциально большое количество элементов данных, , но наСреднее число элементов данных, передаваемых по проводам, меньше максимального, поэтому лучше использовать шаблон свойств.
Вместо определения класса конверта монстра, содержащего все элементы:
// java pseudocode
class envelope
{
field1, field2, field3... field_n;
...
setFields(m1,m2,m3,...m_n){field1=m1; .... };
...
}
Определить словарь (например, на основе карты):
// java pseudocode
public enum EnvelopeField {field1, field2, field3,... field_n);
interface Envelope //package visible
{
// typical map-based read fields.
Object get(EnvelopeField field);
boolean isEmpty();
// new methods similar to existing ones in java.lang.Map, but
// more semantically aligned with envelopes and fields.
Iterator<EnvelopeField> fields();
boolean hasField(EnvelopeField field);
}
// a "marker" interface
// code that only needs to read envelopes must operate on
// these interfaces.
public interface ReadOnlyEnvelope extends Envelope {}
// the read-write version of envelope, notice that
// it inherits from Envelope, but not from ReadOnlyEnvelope.
// this is done to make it difficult (but not impossible
// unfortunately) to "cast-up" a read only envelope into a
// mutable one.
public interface MutableEnvelope extends Envelope
{
Object put(EnvelopeField field);
// to "cast-down" or "narrow" into a read only version type that
// cannot directly be "cast-up" back into a mutable.
ReadOnlyEnvelope readOnly();
}
// the standard interface for map-based envelopes.
public interface MapBasedEnvelope extends
Map<EnvelopeField,java.lang.Object>
MutableEnvelope
{
}
// package visible, not public
class EnvelopeImpl extends HashMap<EnvelopeField,java.lang.Object>
implements MapBasedEnvelope, ReadOnlyEnvelope
{
// get, put, isEmpty are automatically inherited from HashMap
...
public Iterator<EnvelopeField> fields(){ return this.keySet().iterator(); }
public boolean hasField(EnvelopeField field){ return this.containsKey(field); }
// the typecast is redundant, but it makes the intention obvious in code.
public ReadOnlyEnvelope readOnly(){ return (ReadOnlyEnvelope)this; }
}
public class final EnvelopeFactory
{
static public MapBasedEnvelope new(){ return new EnvelopeImpl(); }
}
Нет необходимости устанавливать read-only
внутренние флаги.Все, что вам нужно сделать, это уменьшить ваши экземпляры конвертов до Envelope
экземпляров (которые предоставляют только получатели).
Код, который ожидает чтения, должен работать на конвертах только для чтения, а код, который ожидает изменения полей, должен работать на изменчивых конвертах.Создание фактических экземпляров будет разделено на фабрики.
То есть вы используете компилятор для обеспечения того, чтобы вещи были доступны только для чтения (или позволяли вещам быть изменяемыми), устанавливая некоторые соглашения по коду, правила, определяющие, какие интерфейсыиспользовать где и как.
Вы можете разбить свой код на разделы, которые нужно писать отдельно от кода, который нужно только прочитать.Как только это будет сделано, простые проверки кода (или даже grep) могут идентифицировать код, использующий неправильный интерфейс.)
Проблемы:
Непубличный родительский интерфейс:
Envelope
не объявлен как общедоступный интерфейс, чтобы не допустить, чтобы ошибочный / вредоносный код преобразовывал конверт только для чтения в базовый конверт и затем обратно в изменяемый конверт.Предполагаемый поток - от изменяемого к доступному только для чтения - он не предназначен для двунаправленного.
Проблема в том, что расширение Envelope
ограничено пакетом, в котором оно находится.Будет ли это проблемой, будет зависеть от конкретного домена и предполагаемого использования.
Фабрики:
Проблема в том, что фабрики могут (и, скорее всего, будут) очень сложными.Опять природа зверя.
Проверка:
Другая проблема, связанная с этим подходом, заключается в том, что теперь вам нужно беспокоиться о коде, который ожидает присутствия поля X.Наличие исходного класса конвертов монстров частично освобождает вас от этого беспокойства, потому что, по крайней мере, синтаксически, все поля есть ...
... независимо от того, установлены поля или нет, это был другой вопрос, который все еще остается сэту новую модель, которую я предлагаю.
Так что, если у вас есть клиентский код, который ожидает увидеть поле X, клиентский код должен выдать какой-то тип исключения, если поле отсутствует (или для компьютера или для чтениякак-то разумно по умолчанию.) В таких случаях вам придется
Определить закономерности присутствия поля.Клиенты, которые ожидают, что поле X будет присутствовать, могут быть сгруппированы отдельно (разделены по уровням) от клиентов, которые ожидают присутствие какого-то другого поля.
Связывание пользовательских валидаторов (прокси с интерфейсами конвертов только для чтения)) которые либо генерируют исключения, либо вычисляют значения по умолчанию для пропущенных полей в соответствии с некоторыми правилами (правила предоставляются программно, с интерпретатором или с механизмом правил.)
Отсутствие набора текста:
Это может быть спорным, но люди, привыкшие работать со статической типизацией, могут чувствовать себя неловко, теряя преимущества статической типизации, переходя на слабо типизированный подход на основе карт.Противоположным аргументом этого является то, что большинство веб-сайтов работают по принципу свободной печати, даже на стороне Java (JSTL, EL.)
Проблемы в стороне, чем больше максимальное число возможных полей и тем меньшесреднее количество полей, присутствующих в любой момент времени, наиболее эффективным будет такой подход.Это добавляет дополнительную сложность кода, но это природа зверя.
Эта сложность не исчезнет и будет присутствовать в вашей модели класса или в вашем коде проверки.Сериализация и передача по сети намного эффективнее, особенно, если вы ожидаете огромное количество отдельных передач данных.
Надеюсь, это поможет.