Посоветуйте паттерн/технику для создания класса из базового
От: victor_od  
Дата: 20.12.11 15:22
Оценка:
Задачка по дизайну, но имеет отношение к 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, и скопировать данные из него в конкретный инстанцированный объект


class PriceRecord extends BaseHeader {

    @StaticSizeField( size = 20 )
    private String priceQuoteId;
    @StaticSizeField( size = 4 )
    private Calendar expirationDate;
    // ...

     public PriceRecord() {}
     public PriceRecord( BaseHeader copy ) {
         super(copy)
     }

}


объекты создаются фабрикой, примерно такого вида:


    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 {
    }
    // и тд - можно запрятать в фабричный метод, но там та же суть

    // на выходе - объект конкретного типа, а не Base
    return newObj;




Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса
(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво.
Как можно было бы сделать по другому?

классы — чисто POJO, никакого поведения у них нет
на выходе должен получиться List<BaseHeader> или List<Object> содержащий все инстанцированные объекты из файла



20.12.11 23:57: Перенесено модератором из 'Java' — по просьбе автора — Blazkowicz
java factory
Re: Посоветуйте паттерн/технику для создания класса из базов
От: Blazkowicz Россия  
Дата: 20.12.11 15:30
Оценка:
Здравствуйте, victor_od, Вы писали:

_>Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса

_>(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво.
_>Как можно было бы сделать по другому?

Не понял зачем конструктор к этой задаче приплетать. Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection) и даже напрямую в поля (Reflection + setAccessible(true)).
Re[2]: Посоветуйте паттерн/технику для создания класса из ба
От: victor_od  
Дата: 20.12.11 18:35
Оценка:
B>Не понял зачем конструктор к этой задаче приплетать. Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection) и даже напрямую в поля (Reflection + setAccessible(true)).

через сеттеры придется вызывать для каждого поля, один черт громоздко.
в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле
Re: Посоветуйте паттерн/технику для создания класса из базов
От: avpavlov  
Дата: 20.12.11 18:51
Оценка:
_>Проблема в том что каждый создаваемый класс, должен иметь конструктор, копирующий BaseHeader в поля своего базового класса
_>(что-то вроде "конструктор глубокого копирования" ), это неудобно и не очень красиво.
_>Как можно было бы сделать по другому?

Ты BaseHeader создаёшь для чего, чтобы type вычитать? Ну так вычитывай его из потока отдельной ф-цией, потом создавай сразу объект нужного типа и пусть он парсит всё, включая базовые вещи, тогда не надо будет копированием заниматься.
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
От: avpavlov  
Дата: 20.12.11 18:55
Оценка: +2
_>через сеттеры придется вызывать для каждого поля, один черт громоздко.
_>в 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]: Посоветуйте паттерн/технику для создания класса из ба
От: Blazkowicz Россия  
Дата: 20.12.11 19:02
Оценка: -1
Здравствуйте, victor_od, Вы писали:

_>через сеттеры придется вызывать для каждого поля, один черт громоздко.

Introspector, BeanUtils, Reflection это на столько страшные слова, что не хочется про них читать?

_>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле

Перенести тему в С++ ?
Re[4]: Посоветуйте паттерн/технику для создания класса из ба
От: victor_od  
Дата: 20.12.11 19:31
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, victor_od, Вы писали:


B>Introspector, BeanUtils, Reflection это на столько страшные слова, что не хочется про них читать?


_>>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле

B>Перенести тему в С++ ?

я знаю что такое рефлексия , там нет подобия реализации конструктора копирования.

в философию программирования тогда уж, ибо это недостаток языка
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
От: avpavlov  
Дата: 21.12.11 07:07
Оценка:
_>через сеттеры придется вызывать для каждого поля, один черт громоздко.
_>в c++ Это бы делалось тривиально через дефолтный конструктор копирования , который бы просто скопировал бинарную часть класса поле в поле

Что-то я видать подзабыл уже с++ за 10 лет. Напомни, пожалуйста, как там конструктор копирования "просто копирует бинарную часть" без перечисления всех полей?
Re[2]: Посоветуйте паттерн/технику для создания класса из ба
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 22.12.11 09:29
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection)

Меееедленно. Если десериализовать нужно много, то лучше на каждый десериализуемый класс ASM'мом сгенерить десериализующий класс.

B>и даже напрямую в поля (Reflection + setAccessible(true)).

А вот такой подход мне не нравится, хотя он и применяется много где: стандартный десериализатор, ioc-контейнеры (в том же Java EE) и т.п. Если вручную (через те же сеттеры) никак нельзя установить значения полей объекта, то с тестированием получается жопа. Оправданно оно только в стандартном сериализаторе: если после десериализации объект оказался в некотором состоянии, то, очевидно, в том же состоянии он был при сериализации, т.е. его сериализующая сторона каким-то образом в это состояние перевела. А вот внедрение зависимостей или десериализация какого-нибудь json через открытые поля — явное зло.
Re[3]: Посоветуйте паттерн/технику для создания класса из ба
От: Blazkowicz Россия  
Дата: 22.12.11 10:03
Оценка:
Здравствуйте, konsoletyper, Вы писали:

B>>Значения можно писать через сеттеры (Introspector, BeanUtils, Reflection)

K>Меееедленно.
Рефлексия за последний годы стала очень быстрой. Посмотрите бенчмарки. К тому же, это гораздо быстрее чем передача данных по сети. Поэтому на общую задержку влияние минимальное.

K>Если десериализовать нужно много, то лучше на каждый десериализуемый класс ASM'мом сгенерить десериализующий класс.

Да. Это стандартная оптимизация для процесса сериализации в Java. Только очень скользкая, как и любая кодо-генерация.

K>А вот такой подход мне не нравится, хотя он и применяется много где: стандартный десериализатор, ioc-контейнеры (в том же Java EE) и т.п. Если вручную (через те же сеттеры) никак нельзя установить значения полей объекта, то с тестированием получается жопа. Оправданно оно только в стандартном сериализаторе: если после десериализации объект оказался в некотором состоянии, то, очевидно, в том же состоянии он был при сериализации, т.е. его сериализующая сторона каким-то образом в это состояние перевела. А вот внедрение зависимостей или десериализация какого-нибудь json через открытые поля — явное зло.

С одной стороны правильнее работать со свойствами. Поэтому в инициализирующий контейнерах, инжецкция в поля это зло. Согласен. С другой стороны писать в поля, таки, быстрее. Так что это уже на выбор автора и механизма сериализации.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.