Каков хороший дизайн для обеспечения обратной совместимости файлов между различными версиями программного обеспечения?


14

Каков хороший дизайн для обеспечения обратной совместимости типов файлов между различными версиями программного обеспечения?

Например, как Microsoft получает Word 2007, 2010 и 2013 и т. Д. Во все открытые файлы DOCX, но разные редакции могут сохранять больше / меньше данных и сохранять данные немного по-разному, все в один и тот же тип файла, и файл, сохраненный в одной версии, можно открыть в другой, но некоторые элементы файла могут быть недоступны в более старых версиях?

Я имею в виду, что действительно очевидный способ сделать это -

private string openfile(string filename)
{
    File.Open(filename)

    ... some logic that gets a header from the file that will never change

    switch (fileversion)
        case 2007:
            .....
        case 2010
            .....
        case 2013
            .....
}

но это кажется невероятно монолитным, не очень расширяемым и может привести к большому количеству копируемого / вставляемого кода.

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

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


6
Вы должны спроектировать формат файла так, чтобы он не только игнорировал информацию, которая отсутствует, потому что источник взят из более ранней версии, но также и информацию, которую он не ожидает, потому что источник взят из более новой версии. Если вы начинаете с нуля, пожалуйста, сделайте, пожалуйста, прямую совместимость . Это почти не требует дополнительных усилий и удваивает полезность вашего программного обеспечения.
Килиан Фот

На открытии, вы всегда будете знать заранее (например, из заголовка), с какой версией файла вы имеете дело? Кроме того, чтобы сделать еще один запрос, пожалуйста, проверьте наличие поврежденных или вредоносных файлов и не позволяйте им вызывать проблемы. Ваши сисадмины будут вам благодарны :).
cxw

1
Да, номер версии всегда будет в заголовке файла, и формат заголовка никогда не изменится. Мы идем с идеей, что файлы, созданные между второстепенными версиями программного обеспечения, должны быть совместимы, т.е. файл, созданный в v1.1, может быть открыт в v1.2 и наоборот, хотя некоторые функции из 1.2 могут отсутствовать в 1.1, но основные ревизии нарушит прямую совместимость, поэтому вещи, написанные в v2, не откроются в v1, но вещи, написанные в v1, откроются в v2.
JJBurgess

А что касается повреждения, файлы содержат DSL, и программа, открывающая / закрывающая их, представляет собой собственный IDE / компилятор. Они не будут приближаться к производственной среде, поэтому администратору не нужно беспокоиться.
JJBurgess

Ответы:


10

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


Отличная идея! Формат PNG опирается на функции, а не на версии. Это означает, однако, что основной формат никогда не должен меняться. (то есть заголовок, определяющий особенность.)
Florian Margaine

Это интересно. Я сейчас читаю спецификацию файла. Мне нравится идея критических и вспомогательных кусков, и я мог бы попытаться проработать это.
JJBurgess

3

Для этого можно использовать базовый класс и интерфейс с основными функциями для обработки вашего файла. Затем используйте классы для каждой версии, которые выходят из базового класса, чтобы обрабатывать все случаи, зависящие от версии. Функции, которые могут изменяться, могут быть виртуальными в вашем базовом классе abstract, если существуют только реализации, зависящие от версии. Когда вам нужен класс для обработки файла, используйте фабрику, которая получает специфичную для версии реализацию интерфейса обработки файлов.


Моя единственная проблема с этим заключается в том, что в конечном итоге вы будете дублировать конкретную версию для каждой последующей ревизии. Допустим, у вас есть три метода базового класса: ReadNames (), ReadAges () и ReadAddresses (), а в V2 класса вы вносите изменение в ReadAges (). Если в V3 вы решите внести изменения в ReadNames (), если все ваши классы, зависящие от версии, наследуются от базы, вы потеряете изменения V2 или вам потребуется скопировать / вставить изменения из V2 в реализации V3, а также.
JJBurgess

1
Реализация readages может вызывать другой класс, который содержит фактическую реализацию того, как читать возрасты для этой версии. Создание вашего класса будет больше конфигурации интерфейсов / фабрик, чем фактическое программирование.
сверстник

2

Я сделал это с XML, и он работает хорошо:

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

В будущем, когда вы добавляете новую функцию в новую версию программы, добавьте атрибут или подэлемент. Старые версии будут игнорировать это. Новая версия должна проверять наличие атрибута или подэлемента и обрабатывать его.

Например, у вас есть некоторые элементы с текстом:

<item text="Hello, world!"/>

И в более новой версии вы хотели бы добавить цвет к элементу, чтобы вы добавили атрибут color:

<item text="Hello, world!" color="008000"/>

Старая версия просто игнорирует colorатрибут при открытии документа. Новые версии проверяют наличие colorатрибута и, если не существует, назначают цвет по умолчанию.

С этим простым решением у вас будет как обратная, так и прямая совместимость.


Небольшая проблема с этим «простым» вариантом заключается в том, что при сохранении документа вы удалите все неожиданные атрибуты (или оставите их без изменений). Как уже упоминалось в других ответах, лучшее решение, по крайней мере, каким-то образом определяет независимость от версии относительно того, должен ли атрибут быть удален, сохранен или сделать документ доступным только для чтения для версий, которые его не понимают.
Марк Херд

@ Марк Худр: Да, я молча предполагаю, что обратная совместимость обязательна, а прямая совместимость - бонус. Когда кто-то открывает новый документ в старых версиях приложений, он не должен удивляться, что когда он его сохраняет, он теряет что-то, чего еще не было видно в старом приложении. Дополнительная логика мне кажется слишком сильной.
user3123061
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.