Каков предпочтительный способ хранения разных версий данных? - PullRequest
5 голосов
/ 23 января 2010

Когда вы пишете приложение, которое должно читать и работать с двумя версиями данных одинаково, каков наилучший способ структурировать ваши классы для представления этих данных. Я придумал три сценария:

  1. Общая база / Конкретные дети
  2. Data Union
  3. Отдельные структуры

Пример 1 версии автомобиля

byte DoorCount
int Color
byte HasMoonroof
byte HasSpoiler
float EngineSize
byte CylinderCount

Версия 2 Car

byte DoorCount
int Color
enum:int MoonRoofType
enum:int TrunkAccessories
enum:int EngineType

Общая база / Конкретные дети

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

class Car {
    byte DoorCount;
    int Color;
}

class CarVersion1 : Car {
    byte HasMoonroof;
    byte HasSpoiler;
    float EngineSize;
    byte CylinderCount;
}

class CarVersion2 : Car {
    int MoonRoofType;
    int TrunkAccessories;
    int EngineType;
}

1024 * Сильные стороны *

  • Парадигма ООП

Слабые стороны

  • Существующие дочерние классы должны будут измениться, если будет выпущена новая версия, удаляющая общее поле
  • Данные для одной концептуальной единицы разделены между двумя определениями не из-за какого-либо значимого для нее деления.

Объединение данных

Здесь Car определяется как объединение полей Car во всех версиях данных.

class Car {
    CarVersion version;
    byte DoorCount;
    int Color;
    int MoonRoofType;     //boolean if Version 1
    int TrunkAccessories; //boolean if Version 1
    int EngineType;       //CylinderCount if Version 1
    float EngineSize;     //Not used if Version2
}

Сильные стороны

  • Хм ... Все в одном месте.

Слабые стороны * * тысяча пятьдесят-одна

  • Принудительный регистр, управляемый кодом.
  • Сложно поддерживать, когда выпускается другая версия или удаляется устаревшая.
  • Трудно осмыслить. Значения полей изменились в зависимости от версии.

Отдельные структуры

Здесь структуры не имеют ООП-отношений друг с другом. Однако интерфейсы могут быть реализованы обоими классами, если / когда код ожидает, что они будут обрабатывать их одинаково.

class CarVersion1 {
    byte DoorCount;
    int Color;
    byte HasMoonroof;
    byte HasSpoiler;
    float EngineSize;
    byte CylinderCount;
}

class CarVersion2 {
    byte DoorCount;
    int Color;
    int MoonRoofType;
    int TrunkAccessories;
    int EngineType;
}

Сильные стороны

  • Простой подход
  • Простота обслуживания, если добавлена ​​новая версия или удалено устаревшее.

Слабые стороны

  • Это анти-паттерн.

Есть ли лучший способ, о котором я не думал? Вероятно, очевидно, что я предпочитаю последнюю методологию, но лучше ли первая?

Ответы [ 3 ]

1 голос
/ 24 января 2010

используйте второй подход и дополните его интерфейсами. Помните, что вы можете реализовать несколько «версий» интерфейсов, что дает вам возможность обратной совместимости! я надеюсь, что вы получите то, что я хотел сказать;)

1 голос
/ 24 января 2010

Соблюдается следующее требование:

приложение, которое должно читать и работать с двумя версиями данных одинаково

Я бы сказал, что самым важным является то, что вы направляете всю логику через уровень абстракции данных, так что ни одна из вашей логики не будет заботиться о том, используете ли вы версию 1, 2 или n данных.

Один из способов сделать это - иметь только один класс данных, который является самой «зашифрованной» версией данных. По сути, он будет иметь MoonRoofType, но не HasMoonRoof, поскольку это может быть выведено. Этот класс также не должен иметь каких-либо устаревших свойств, поскольку именно уровень абстракции данных определяет, какими должны быть значения по умолчанию.

В конце концов, у вас будет приложение, которое не заботится о версиях данных.

Что касается уровня абстракции данных, вы можете или не хотите иметь классы данных для каждой версии. Скорее всего, все, что вам понадобится, - это один класс для каждой версии структуры данных с Save и Load методами для хранения / создания экземпляров данных, используемых логикой вашего приложения.

1 голос
/ 23 января 2010

Почему третий вариант, отдельные структуры для каждой версии, плохая идея или анти-паттерн?

Если две версии структур данных используются в общем приложении / модуле - им придется реализовать один и тот же интерфейс. Период. Определенно невозможно написать два разных модуля приложения для обработки двух разных версий структуры данных. Тот факт, что базовая модель данных чрезвычайно отличается, не должен иметь значения. В конце концов, целью написания объектов является достижение практического уровня инкапсуляции.

Поскольку вы продолжаете писать код таким образом, вы должны в конечном итоге найти места, где код в обоих классах похож или избыточен. Если вы удалите эти общие части кода из различных классов версий, вы можете в конечном итоге получить классы версий, которые не только реализуют один и тот же интерфейс, но также могут реализовать один и тот же базовый / абстрактный класс. Вуаля, вы нашли свой «первый» вариант.

Я думаю, что это лучший путь в среде с постоянно развивающимися данными. Это требует некоторого усердия и «оглядки» на старый код, но стоит преимуществ ясности кода и повторно используемых компонентов.

Еще одна мысль: в вашем примере базовый класс - «Автомобиль». На мой взгляд, вряд ли когда-нибудь окажется, что базовый класс настолько "близок" к своим наследникам. Более реалистичный набор базовых классов или интерфейсов может быть «Versionable», «Upgradeable», «OptionContainer» и т. Д. Просто, исходя из моего опыта, YMMV.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...