Управление версиями класса для поддержки назад совместимости

В проекте я продолжаю работать, мы обрабатываем Медицинскую тарификацию.

Каждый раз состояние вносит изменение в официальную форму (который наши классы данных представляют), для поддержания обратной совместимости с предыдущими формами, мы добавляем новые свойства, но оставляем старые неповрежденными, и имеем свойство версии документа, которое используется для определения, какая проверка сделана и действия UI для отображения его.

Это имеет вывод к чрезмерно увеличенным в размерах классам по сроку действия проекта (почти 5 лет переданных под мандат состоянием изменений), и просто не поддержка старых форматов документов не является опцией.

Я хотел бы попытаться создать новый класс для каждой версии документа, но даже тогда у нас будет несколько копий очень похожих (хотя немного изменено) кодом. И имена классов, такие как ProgressNoteV16, ProgressNoteV17 выглядят ужасными.

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

Что решения и лучшие практики используются для решения этой проблемы?

10
задан Muad'Dib 29 December 2009 в 20:52
поделиться

4 ответа

Это довольно классическая проблема для любого агентства, которое работает с общественностью в любом качестве, особенно если это государственное или контролируемое правительством агентство. Решение нетривиально, и, вероятно, для его создания, а также последующего сопровождения потребуется значительная работа.

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

Есть пара паттернов, с которыми стоит познакомиться (если вы еще не знакомы):

  1. Factory, о котором уже упоминалось ранее
  2. Composition, которые, будем надеяться, вытащат вас из некоторых уродливых проблем с наследованием
  3. Template для отделения логики того, что делает форма, от версий

Есть две книги, которые довольно хорошо объясняют эти (и несколько других полезных):

  1. Head First Design Patterns (Cant remember off the top of my head)
  2. Patterns of Enterprise Application Architecture (Fowler)

Теперь к процессу, который я использовал в прошлом:

  1. Начните с того, что возьмите все ваши текущие версии форм, разделите их на различные классы и ищите общее перекрытие. Вы можете сделать это в черновом режиме или по мере того, как Вы планируете иметь различные классы для каждой версии
  2. Выделите из структуры этого класса ряд "базовых" объектов, которые Вы можете использовать в качестве корня наследования для каждого значительного набора версий формы. У вас может быть несколько таких объектов, но их должно быть меньше, чем у вас в целом.
  3. Теперь в каждом из этих базовых объектов сгруппируйте общую функциональность (т.е. структуры имен и адресов и т.д.) и абстрагируйте это в свою собственную классовую иерархию, впрысните эту иерархию обратно в свои базовые классы с помощью инжекции конструктора.
  4. Применяйте шаблон композиции к своей базовой иерархии классов сейчас и работайте над тем, чтобы получить как можно больше общей классовой структуры. В идеале, ваши формы на данном этапе должны быть просто минимальной функциональностью, которая изменилась в каждой форме, и иметь конструктор, который берет всю общую (и, возможно, слегка отличающуюся) функциональность.
  5. Применить шаблон Template сейчас, чтобы абстрагироваться от всей общей "функциональности" ваших классов, такой как общая валидация и логика персистентности, используйте инъекцию конструктора снова, чтобы вернуть эту функциональность в ваши базовые классы.
  6. Извлеките определения адаптеров интерфейса из ваших базовых классов и используйте их в качестве основы для работы вашего приложения с вашими формами
  7. Постройте свои заводские классы, чтобы справиться со всей этой громоздкой работой по настройке.

Надеюсь, это даст вам некоторые идеи о том, что делать.

8
ответ дан 4 December 2019 в 01:31
поделиться

Если наследование не может быть использовано "потому что поля в документе могут быть удалены", как вы это делаете в настоящее время?

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

Вы можете использовать Factory Pattern, чтобы вернуть соответствующий экземпляр объекта для данной версии формы.

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

Что касается именования классов, то если вы используете заводскую схему, то вы можете обратиться к классу в большинстве своего кода, используя интерфейс. Только на заводе придется иметь дело с "странными" именами классов.

.
2
ответ дан 4 December 2019 в 01:31
поделиться

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

.
0
ответ дан 4 December 2019 в 01:31
поделиться

зависит от вашего контракта и вашего конкретного случая . Обычно лучше всего возвращать пустые коллекции , но иногда ( редко ):

  • null может означать что-то более конкретное;
  • ваш API (контракт) может заставить вас вернуть null.

Некоторые конкретные примеры:

  • компонент пользовательского интерфейса (из библиотеки, не контролируемой вами), может отрисовывать пустую таблицу, если передана пустая коллекция, или вообще никакую таблицу, если передан ноль.
  • в объекте-XML (JSON/weverever), где null означал бы, что элемент отсутствует, .. Взгляните на эту статью: Избегайте чрезмерного разделения на подклассы с помощью шаблона дизайна декоратора

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

    .
0
ответ дан 4 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: