Разделение пользовательского интерфейса и логики в C # - PullRequest
13 голосов
/ 25 июня 2010

У кого-нибудь есть советы по поводу того, чтобы не пускать логику в мои классы GUI?Я стараюсь использовать хороший дизайн классов и держу их как можно дальше друг от друга, но мои классы Form обычно содержат больше не-пользовательского интерфейса, чем хотелось бы, и это приводит к тому, что обслуживание становится настоящей болью.1002 * (Visual Studio 2008 Professional, C #, приложения для Windows).

Большое спасибо.

Ответы [ 8 ]

12 голосов
/ 25 июня 2010

Поместите свою логику в отдельную сборку;и собрать эту сборку без ссылки на какие-либо пакеты графического интерфейса (например, System.Drawing, System.Windows.Forms и т. д.).

6 голосов
/ 25 июня 2010

Это действительно просто вопрос практики и самодисциплины. Я имею в виду, мы все сделали это. И мы все время от времени продолжаем делать это в неправильных условиях (менеджер / клиент кричит, чтобы что-то было сделано «прямо сейчас» против «правильно» и т. Д.).

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

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

4 голосов
/ 25 июня 2010

Трехслойная архитектура - это то, что вы ищете.

Вы строите 2 многоразовых слоя:

  • Уровень доступа к данным (DAL), который содержит только код, необходимый для чтение / запись из базы данных
  • Уровень бизнес-логики (BLL), который потребляет DAL, содержит бизнес правила, проверка и обеспечивает фасад для использования интерфейса

Затем в вашем UI-проекте вы ссылаетесь на повторно используемые слои и обрабатываете только специфичные для UI вещи. Проект пользовательского интерфейса общается только с BLL, без прямой связи с DAL:

UI <---> BLL <---> DAL

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

4 голосов
/ 25 июня 2010

Вы должны посмотреть на шаблоны дизайна, такие как:

Model-View-Controller (MVC), часто используемый веб-сайтами (ASP.NET)
Модель-Вид-Вид Модель (MVVM), часто используемая WPF

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

Существуют и другие шаблоны, выполняющие аналогичную работу.

Кроме того, разработка с использованием WPF может помочь, поскольку пользовательский интерфейс определяется XAML, а код, выполняющий эту работу, - это C #. Это может обеспечить базовую степень разделения. Если вы обнаружите, что пишете код C #, который просто манипулирует пользовательским интерфейсом, вы можете сделать шаг назад и подумать: «Должен ли я сделать это в XAML?» Очевидно, что в коде есть кое-что, что вам нужно сделать, но это только начало.

1 голос
/ 25 июня 2010

Одним словом, это называется Рефакторинг .

Существует только несколько причин для добавления кода в пользовательский интерфейс:

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

Весь другой код "Бизнес-логики" входит в другой класс, называемый классом бизнес-логики. Весь код взаимодействия с БД переходит в другой класс, называемый классом доступа к данным.

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

Ознакомьтесь с некоторыми книгами Мартина Фаулера по рефакторингу, например, «Рефакторинг: улучшение дизайна существующего кода». Другое модное слово - разделение проблем. Я знаю, что вы можете делать все это в одном классе, но код становится намного более читабельным и его легче отлаживать, когда он разделен на классы, как я описал выше.

1 голос
/ 25 июня 2010

Узнайте, как писать классы контроллеров, которые могут быть привязаны к форме данных, и как выполнять привязку данных.В WinForms это в основном сводится к интерфейсам INotifyPropertyChanged и IDataErrorInfo в классе контроллера и к использованию экземпляров BindingSource в классе формы.

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

Этооснова всех конструкций MVC / MVVM.

Херби

0 голосов
/ 25 июня 2010

Вы должны взглянуть на следующие шаблоны:

MVC (Model-View-Controller) MVVM (Model-View-View-Model) - в основном используется в WPF с его богатой поддержкой привязки данных.MVP (Model-View-Presenter) - часто используется для WinForms и веб-приложений (из-за представления без сохранения состояния)

Ознакомьтесь с этим сообщением в блоге, в котором приведен пример того, как использовать MVP для питания как сети, так и WinFormsпросмотр с одним докладчиком: http://www.cerquit.com/blogs/post/MVP-Part-I-e28093-Building-it-from-Scratch.aspx

Кроме того, в следующем посте здесь описывается использование шаблона MVP для модульного тестирования вашей бизнес-логики: http://www.cerquit.com/blogs/post/Model-View-Presenter-Part-II---Unit-Testing.aspx

0 голосов
/ 25 июня 2010

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

Что касается разделения логики; определите, какие компоненты являются ключевыми, и перенесите их в класс вспомогательных методов. Например; если я обрабатываю GridView для обновления записей в зависимости от того, выбраны они или нет; и если они есть, обновите ShipDate, в форме; я бы сначала выяснил, выбрана ли строка; затем извлеките поле Id, затем ShipDate, а затем передайте Id и ShipDate в метод моего вспомогательного класса, который выполняет всю работу.

Модульные тесты могут быть вашими друзьями здесь; в основном, если у вас есть какой-нибудь код, который делает вещи типа «логика» у него должен быть модульный тест. Если это в классах GUI; это сложно проверить; однако, как только вы реорганизуете его; модульный тест должен быть тривиальным.

...