Задачка по дизайну, но имеет отношение к Java, поскольку реализовать надо на Java
Разрабатываю библиотеку/фреймворк для десериализации дерева объектов из бинарного формата
В общем , нужно отобразить некий бинарный формат на дерево POJO классов.
Сами классы имеют аннотации, чтобы парсер понимал размер поля и его смещение в бинарном файле.
каждый объект имеет заголовок, который одинаков по структуре,
и переменную часть, которая зависит от фактического типа объекта
если это моделировать наследованием — получается вот так
class BaseHeader {
@BaseOffset( offset = 20 )
@StaticSizeField( size = 2 )
private int length;
@StaticSizeField( size = 2 )
private int type;
@StaticSizeField( size = 3 )
private byte[] uuid = new byte[3];
// ... и еще куча разных свойствpublic BaseHeader(BaseHeader copy) {
// "copy constructor"
setLength(copy.getLength() );
setType( copy.getType() ) ;
//... а можно это делать проще? не перечисляя каждую property
}
}
тип объектов, которые создаются, определяется в рантайме, из поля type в объекте BaseHeader
т.е. в рантайме мне нужно создать объект типа PriceRecord (или NameRecord, или любого другого),
но сначала нужно создать BaseHeader, и скопировать данные из него в конкретный инстанцированный объект
BaseHeader header= new BaseHeader();
TreeParser parser = new TreeParser();
parser.populateObject( header, bufferSource );
BaseHeader newObj = null;
if( header.getType() == 0x01 ) {
newObj = new PriceRecord(header);
parser.populateObject( newObj, bufferSource);
}
else if( header.getType() == 0x02 ) {
newObj = new NameRecord(header);
parser.populateObject( newObj, bufferSource);
}
else if( header.getType() == 0x04 ) {
newObj = new TicketRecord(header);
parser.populateObject( newObj, bufferSource);
}
else {
}
// и тд - можно запрятать в фабричный метод, но там та же суть
// на выходе - объект конкретного типа, а не Basereturn newObj;
Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса
(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво.
Как можно было бы сделать по другому?
классы — чисто POJO, никакого поведения у них нет
на выходе должен получиться List<BaseHeader> или List<Object> содержащий все инстанцированные объекты из файла
20.12.11 23:57: Перенесено модератором из 'Java' — по просьбе автора — Blazkowicz
Здравствуйте, victor_od, Вы писали:
_>Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса _>(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво. _>Как можно было бы сделать по другому?
Не понял зачем конструктор к этой задаче приплетать. Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection) и даже напрямую в поля (Reflection + setAccessible(true)).
Re[2]: Посоветуйте паттерн/технику для создания класса из ба
B>Не понял зачем конструктор к этой задаче приплетать. Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection) и даже напрямую в поля (Reflection + setAccessible(true)).
через сеттеры придется вызывать для каждого поля, один черт громоздко.
в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле
Re: Посоветуйте паттерн/технику для создания класса из базов
_>Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса _>(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво. _>Как можно было бы сделать по другому?
Ты BaseHeader создаёшь для чего, чтобы type вычитать? Ну так вычитывай его из потока отдельной ф-цией, потом создавай сразу объект нужного типа и пусть он парсит всё, включая базовые вещи, тогда не надо будет копированием заниматься.
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
_>через сеттеры придется вызывать для каждого поля, один черт громоздко. _>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле
ну так не копируй, а храни как есть
public AbstractRecord {
private BaseRecord header;
public AbstractRecord(BaseRecord header) {
this.header = header;
}
public BaseHeader getHeader() {
return header;
}
}
public PriceRecord extends AbstractRecord{
public PriceRecord(BaseRecord header) {
super(header);
}
}
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
Здравствуйте, victor_od, Вы писали:
_>через сеттеры придется вызывать для каждого поля, один черт громоздко.
Introspector, BeanUtils, Reflection это на столько страшные слова, что не хочется про них читать?
_>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле
Перенести тему в С++ ?
Re[4]: Посоветуйте паттерн/технику для создания класса из ба
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, victor_od, Вы писали:
B>Introspector, BeanUtils, Reflection это на столько страшные слова, что не хочется про них читать?
_>>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле B>Перенести тему в С++ ?
я знаю что такое рефлексия , там нет подобия реализации конструктора копирования.
в философию программирования тогда уж, ибо это недостаток языка
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
_>через сеттеры придется вызывать для каждого поля, один черт громоздко. _>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле
Что-то я видать подзабыл уже с++ за 10 лет. Напомни, пожалуйста, как там конструктор копирования "просто копирует бинарную часть" без перечисления всех полей?
Re[2]: Посоветуйте паттерн/технику для создания класса из ба
Здравствуйте, Blazkowicz, Вы писали:
B>Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection)
Меееедленно. Если десериализовать нужно много, то лучше на каждый десериализуемый класс ASM'мом сгенерить десериализующий класс.
B>и даже напрямую в поля (Reflection + setAccessible(true)).
А вот такой подход мне не нравится, хотя он и применяется много где: стандартный десериализатор, ioc-контейнеры (в том же Java EE) и т.п. Если вручную (через те же сеттеры) никак нельзя установить значения полей объекта, то с тестированием получается жопа. Оправданно оно только в стандартном сериализаторе: если после десериализации объект оказался в некотором состоянии, то, очевидно, в том же состоянии он был при сериализации, т.е. его сериализующая сторона каким-то образом в это состояние перевела. А вот внедрение зависимостей или десериализация какого-нибудь json через открытые поля — явное зло.
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
Здравствуйте, konsoletyper, Вы писали:
B>>Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection) K>Меееедленно.
Рефлексия за последний годы стала очень быстрой. Посмотрите бенчмарки. К тому же, это гораздо быстрее чем передача данных по сети. Поэтому на общую задержку влияние минимальное.
K>Если десериализовать нужно много, то лучше на каждый десериализуемый класс ASM'мом сгенерить десериализующий класс.
Да. Это стандартная оптимизация для процесса сериализации в Java. Только очень скользкая, как и любая кодо-генерация.
K>А вот такой подход мне не нравится, хотя он и применяется много где: стандартный десериализатор, ioc-контейнеры (в том же Java EE) и т.п. Если вручную (через те же сеттеры) никак нельзя установить значения полей объекта, то с тестированием получается жопа. Оправданно оно только в стандартном сериализаторе: если после десериализации объект оказался в некотором состоянии, то, очевидно, в том же состоянии он был при сериализации, т.е. его сериализующая сторона каким-то образом в это состояние перевела. А вот внедрение зависимостей или десериализация какого-нибудь json через открытые поля — явное зло.
С одной стороны правильнее работать со свойствами. Поэтому в инициализирующий контейнерах, инжецкция в поля это зло. Согласен. С другой стороны писать в поля, таки, быстрее. Так что это уже на выбор автора и механизма сериализации.