Здравствуйте, Angler, Вы писали:
A>Здравствуйте, Шахтер, Вы писали:
Ш>>Как здесь обойтись одним общим методом (одно решение я знаю, но подсказывать не буду)?
A>
A>void ReadWrite(IStream *stream)
A>{
A> stream->ReadWrite(counter);
A> if(stream->IsReading())
A> {
A> checkInvariant();
A> }
A>}
A>void checkInvariant()
A>{
A> if(counter < MinCounter || counter > MaxCounter)
A> throw std::range_error("class RepeatCounter : out of bound");
A>}
A>
A>
Да. Но только вызов checkInvariant должен не в методе происходить, а делаться deserialization framework ом.
К сожалению, этот метод тоже не универсален.
Вот простейший пример.
class SomeClass
{
vector<int> data;
...
public:
template <class Dev>
void serialize(Dev &dev) const
{
size_t n=data.size();
dev << n ;
for(size_t i=0; i<n ;i++) dev << data[i] ;
}
template <class Dev>
void deserialize(Dev &dev)
{
size_t n;
dev >> n ;
if( n>MaxDataSize )
throw range_error("...");
{
vector<int> temp(n);
swap(data,temp);
}
for(size_t i=0; i<n ;i++) dev >> data[i] ;
}
};
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, Angler, Вы писали:
A>>Здравствуйте, Шахтер, Вы писали:
Ш>>>Как здесь обойтись одним общим методом (одно решение я знаю, но подсказывать не буду)?
A>>
A>>
Ш>Да. Но только вызов checkInvariant должен не в методе происходить, а делаться deserialization framework ом.
Ш>К сожалению, этот метод тоже не универсален. Ш>Вот простейший пример.
для этого делаем адаптер для вектора, и SomeClass превращается в Composite:
template<typename T>
class PersistentVector : public std::vector<T>
{
public:
void ReadWrite(IStream *stream)
{
...
}
};
class SomeClass
{
PersistentVector<int> data;
public:
void ReadWrite(IStream *stream)
{
data.ReadWrite(stream);
}
};
остается подумать, как организовать интерфейсы SomeClass и PersistentVector для удобной проверки любых условий.
Но я так и не понял, чем просто проверка на тип операции плоха?
Здравствуйте, Angler, Вы писали:
A>остается подумать, как организовать интерфейсы SomeClass и PersistentVector для удобной проверки любых условий.
Неоправдано сложно. Проще реализовать в SomeClass раздельные методы для сериализации и десериализации.
A>Но я так и не понял, чем просто проверка на тип операции плоха?
Тем что её надо писать в каждом классе тогда. И тем что она динамическая, тогда как что мы делаем известно в compile-time. Если этот вызов вставить в реализацию десеариализации, то написать надо будет один раз, а классу останется просто реализовать метод.
A>
A>class SomeClass
A>{
A> void ReadWrite(IStream *stream)
A> {
A> //read-write data
A> {
A> size_t vectorSize = data.size();
A> stream->ReadWrite(vectorSize);
A> if(stream->IsReading()(
A> {
A> if(n > MaxDataSize)
A> throw range_error("...");
A> data.resize(vectorSize);
A> }
A> stream->ReadWrite(vector.begin(), vector.end());
A> }
A> }
A>};
A>
Мне категорически не нравятся попытки слить два метода, делающие довольно-таки разную работу.
Если коротко резюмировать:
1) механизм сериализации/десериализации должен быть гибким, т.е.
если класс определяет два метода serialize и deserialize, то использовать
serialize для сериализации, а deserialize для десериализации
если класс определяет только один метод serialize, то использовать его и для
сериализации, и для десериализации
если класс определяет метод check_deserialized, то использовать его для
проверки корректности десериализации
2) Если класс простой, то можно использовать один метод, в сложных случаях,
когда десериализация значительно отличается от сериализации, лучше
использовать раздельные методы.
Здравствуйте, Angler, Вы писали:
A>Здравствуйте, Шахтер, Вы писали:
Ш>>Если коротко резюмировать:
A>В принципе я согласен, но хочу добавить, что имея два метода, проще сделать ошибку(например если перепутать порядок или забыть какое-то поле).