Поддержка и развертывание двух версий приложения одновременно
У меня есть приложение C# WinForms в Visual Studio 2010, которое используется двумя разными клиентами. Основные функциональные возможности приложения одинаковы для каждого клиента, но определенные строки кода (имена хранимых процедур, ресурсов, определенные поведения) различаются в разных версиях. До сих пор я держал приложение в том же проекте и использовал директивы препроцессора при сборке / публикации для переключения между используемым развертыванием. Однако масштабы проекта выросли до такой степени, что это уже невозможно.
Поскольку большая часть кода является общей, я стараюсь избегать дублирования файлов исходного кода. Мне интересно, какой лучший подход заключается в поддержке приложения, которое требует одновременного развертывания разных версий.
3 ответа
Используйте интерфейсы для определения ваших классов. Наличие интерфейса означает, что вы можете иметь несколько реализаций одного и того же интерфейса, по одному для каждого из клиентов. Это потребует от вас анализа существующей кодовой базы и определения логического разделения в вашем коде, где эти интерфейсы могут быть определены.
Затем у вас есть возможность загрузить интерфейс по мере необходимости на основе клиента. Вы можете, например, сделать это с помощью конфигурации. На основании значения конфигурации вы загружаете реализацию1 или реализацию2. Есть много, много способов сделать это. Вы должны прочитать о внедрении зависимостей, инверсии управления и взглянуть на такие инструменты, как Ninject, Autofac, Unity.
Сначала это может быть сложно, учитывая, как вы использовали директивы препроцессора, но, учитывая, как растет ваше приложение, вам понадобится этот рефакторинг. Имейте в виду, что если вы не сделаете это сейчас, этот рефакторинг будет намного дороже, поскольку ваше приложение становится более сложным.
Различные функциональные возможности должны быть частью архитектуры приложения. Если вам нужны разные функциональные возможности для разных клиентов, абстрагируйте их - создайте интерфейс, который оборачивает поведение, затем реализуйте его двумя различными способами в двух разных сборках. Затем (в зависимости от вашего механизма развертывания) вы можете отправить свое приложение либо с одной DLL, либо с другой. Чтобы избежать перекомпиляции, добавления ссылок и т. Д., Вы можете использовать каркас Dependency Injection, такой как Ninject, Castle Windsor, MEF и т. Д. Это "плагиноподобная" архитектура, если код достаточно отличается.
Если вы говорите о тексте, цветах, основных различиях, они должны просто не быть жестко закодированы, а основаны на данных. Если ваше приложение подключено к Интернету, оно может загружать соответствующие настройки при входе пользователя в систему. В противном случае что-то для обозначения текста / цвета / поведения может быть помещено в файл конфигурации, специфичный для клиента. Вы можете использовать преобразования config, чтобы упростить этот процесс.
Возможно, вам удастся отделить некоторые из различий, используя какие-либо файлы ресурсов, конфигурации или свойств. Под этим я подразумеваю, что вы сохраняете какое-то значение в файле, например, имя хранимой процедуры для использования в конкретной ситуации. Затем ваш код читает имя из файла и запускает его. Вы можете изменить значения в файле без необходимости перестраивать свой код для каждого развертывания.