Архитектура корпоративных приложений WPF / Silverlight. Что вы делаете? - PullRequest
3 голосов
/ 28 октября 2011

Мне было интересно, что живет в сообществе уже довольно давно; Я говорю о больших бизнес-ориентированных корпоративных приложениях WPF / Silverlight.

Теоретически, в игре есть разные модели:

  • Модель данных (обычно связанная с вашими таблицами БД, сущностями Edmx / NHibarnate / .. mapped)
  • Бизнес-модель (классы, содержащие актуальную бизнес-логику)
  • Модель передачи (классы (dto's), открытые для внешнего мира / клиента)
  • Модель представления (классы, к которым привязаны ваши фактические представления)

Совершенно очевидно, что это разделение имеет свои очевидные преимущества; Но работает ли это в реальной жизни? Это кошмар обслуживания?

Так что вы делаете? На практике вы используете разные модели классов для всех этих моделей? Я видел много вариантов этого, например:

  • Модель данных = Бизнес-модель: Модель данных сначала реализовала код (как POCO), а также использовала его как бизнес-модель с бизнес-логикой
  • Бизнес-модель = Модель переноса = Модель просмотра: бизнес-модель как таковая предоставляется клиенту; Нет сопоставления с DTO, .. не происходит. Представление привязывается непосредственно к этой бизнес-модели
  • Silverlight RIA Services, из коробки с открытой моделью данных: Модель данных = Бизнес-модель = Модель переноса. А иногда даже Transfer Model = View Model.
  • ..

Я знаю, что ответ "все зависит" здесь; Но от чего это зависит тогда; Какие подходы вы использовали и как вы оглядываетесь на это?

Спасибо, что поделились,

С уважением, Koen

Ответы [ 4 ]

2 голосов
/ 28 октября 2011

Хороший вопрос. Я никогда не кодировал ничего по-настоящему предприимчивого, поэтому мой опыт ограничен, но я начну.

В моем текущем проекте (WPF / WCF) используется Модель данных = Бизнес-модель = Модель переноса = Просмотреть модель! Бэкэнда БД нет, поэтому «модель данных» - это бизнес-объекты, сериализованные в XML.

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

И моим бизнес-объектам, и объектам представления требовалось push-уведомление об изменениях значений, поэтому имело смысл реализовать их одним и тем же методом (INotifyPropertyChanged). Это имеет приятный побочный эффект, что мои бизнес-объекты могут быть напрямую связаны с представлениями WPF, хотя использование MVVM означает, что ViewModel может легко предоставить оболочки, если это необходимо.

До сих пор я не сталкивался с какими-либо серьезными препятствиями, а наличие одного набора объектов для обслуживания делает вещи красивыми и простыми. Страшно подумать, насколько масштабным будет этот проект, если я разделю все четыре «модели».

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

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

0 голосов
/ 28 октября 2011

Мы используем подход, подобный тому, который выложил Purplegoldfish с несколькими дополнительными слоями.Наше приложение связывается в основном с веб-сервисами, поэтому наши объекты данных не привязаны к какой-либо конкретной базе данных.Это означает, что изменения схемы базы данных не обязательно должны влиять на пользовательский интерфейс.

У нас есть уровень пользовательского интерфейса, состоящий из следующих подуровней:

  1. Модели данных:Это включает в себя простые объекты данных, которые поддерживают уведомления об изменениях.Это модели данных, используемые исключительно в пользовательском интерфейсе, поэтому мы можем гибко разрабатывать их в соответствии с потребностями пользовательского интерфейса.Или, конечно, некоторые из этих объектов не просты, поскольку содержат логику, которая манипулирует их состоянием.Кроме того, поскольку мы используем множество сеток данных, каждая модель данных отвечает за предоставление списка свойств, которые можно привязать к сетке.

  2. Представления: наши определения представлений в XAML,Чтобы приспособиться к некоторым сложным требованиям, нам пришлось прибегнуть к коду позади в некоторых случаях, так как придерживаться подхода только на XAML было слишком утомительно.

  3. ViewModels: Здесь мы определяем бизнес-логику для нашегоПросмотры.Эти ребята также имеют доступ к интерфейсам, которые реализованы сущностями на нашем уровне доступа к данным, описанному ниже.

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

Затем у нас есть слой доступа к данным, который содержит следующее:

  1. Передача объектов: обычно это объекты данных, предоставляемые веб-сервисами.Большинство из них генерируются автоматически.

  2. Адаптеры данных, такие как клиентские прокси-серверы WCF и прокси-серверы к любому другому удаленному источнику данных: эти прокси-серверы обычно реализуют один или несколько интерфейсов, доступных для ViewModels, и отвечают завсе асинхронные вызовы к удаленному источнику данных, при необходимости переводя все ответы в модели данных, эквивалентные пользовательскому интерфейсу.В некоторых случаях мы используем AutoMapper для перевода, но все это делается исключительно в этом слое.Наш многоуровневый подход немного сложен, так же как и применение.Он имеет дело с различными типами источников данных, включая веб-сервисы, прямой доступ к базе данных и другие типы источников данных, такие как веб-сервисы OGC.

0 голосов
/ 28 октября 2011

Несколько слоев не приводят к кошмару обслуживания, кроме того, чем меньше у вас слоев - тем легче их поддерживать. И я постараюсь объяснить, почему.

1) Модель переноса не должна совпадать с моделью данных

Например, у вас есть следующая сущность в вашей модели данных сущности ADO.Net:

Customer
{
    int Id
    Region Region
    EntitySet<Order> Orders
}

И вы хотите вернуть его из службы WCF, поэтому вы пишете такой код:

dc.Customers.Include("Region").Include("Orders").FirstOrDefault();

И есть проблема: как потребители будут уверены, что свойства Region и Orders не равны нулю или не пусты? И если у сущности Order есть коллекция OrderDetail сущностей, они тоже будут сериализованы? А иногда вы можете забыть отключить отложенную загрузку, и весь граф объектов будет сериализован.

И некоторые другие ситуации:

  • вам нужно объединить две сущности и вернуть их как один объект.

  • вы хотите вернуть только часть сущности, например всю информацию из таблицы File, кроме столбца FileContent типа двоичного массива.

  • вы хотите добавить или удалить некоторые столбцы из таблицы, но не хотите предоставлять новые данные существующим приложениям.

Так что я думаю, что вы убеждены, что автоматически созданные объекты не подходят для веб-сервисов. Вот почему мы должны создать такую ​​модель передачи:

class CustomerModel
{
    public int Id { get; set; }
    public string Country { get; set; }
    public List<OrderModel> Orders { get; set; }
}

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

Чтобы упростить процесс преобразования моделей, вы можете использовать библиотеку AutoMapper .

2) Рекомендуется, чтобы View Model не была такой же, как Transfer Model

Хотя вы можете привязать объект модели переноса непосредственно к представлению, это будет только отношение «OneTime»: изменения модели не будут отражены в представлении и наоборот. Класс модели представления в большинстве случаев добавляет к классу модели следующие функции:

  • Уведомление об изменениях свойств с использованием интерфейса INotifyPropertyChanged

  • Уведомление об изменениях коллекции с использованием ObservableCollection класса

  • Проверка свойств

  • Реакция на события представления (с использованием команд или комбинации привязки данных и установщиков свойств)

  • Преобразование свойств, аналогично {Binding Converter...}, но на стороне модели вида

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

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

0 голосов
/ 28 октября 2011

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

Этот проект был

  • Модель данных (базовые классы без поддержки InotifyPropertyChanged),
  • Модель представления (поддерживает INPC, вся бизнес-логика для связанного представления),
  • Просмотр (только XAML),
  • Модель передачи (Методы только для вызова базы данных)

Я классифицировал модель Transfer как одну вещь, но на самом деле она была построена в несколько слоев.

У меня также была серия классов ViewModel, которые были обертками вокруг классов Model, чтобы либо добавить дополнительную функциональность, либо изменить способ представления данных. Все они поддерживали INPC и были теми, к которым привязан мой пользовательский интерфейс.

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

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

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

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

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

...