Круговая зависимость между «контроллером» и «графическим интерфейсом» - PullRequest
6 голосов
/ 03 ноября 2011

Я пишу сложный графический интерфейс на Java со многими компонентами на нескольких экранах, работающих поверх и взаимодействующих с общей частью логики и модели.Ясно, что существуют некоторые циклические зависимости между «графическим интерфейсом» и «контроллером / логикой»: пользовательские действия в графическом интерфейсе перенаправляются на контроллер, который выполняет некоторую задачу и затем должен отражать эти изменения во всех графических интерфейсах.Что-то может произойти в фоновом режиме, что заставляет контроллер выдвигать обновления для графического интерфейса.И так далее.

Теперь вот мой вопрос.Шаблон «слушатель» или «наблюдатель» отлично подходит для отправки обновлений в графический интерфейс.Можно ли сделать так, чтобы мой графический интерфейс напрямую зависел от конкретного класса контроллера?Почему, почему нет?Существует (и всегда будет) только один такой контроллер.Есть как дюжина вызовов контроллера, которые нужны GUI для опроса состояния и выполнения действий - мне не нравится идея горстки тривиальных интерфейсов обратного вызова, которая всегда будет иметь только одну реализацию, или один гигантский интерфейс обратного вызова для всехвиды действий.

Ответы [ 3 ]

6 голосов
/ 03 ноября 2011

Это нормально, чтобы мой графический интерфейс зависел от конкретного класса контроллера напрямую? Почему / почему нет?

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

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

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

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

Круговые зависимости между графическим интерфейсом и контроллером в порядке (для абстракций!). Есть много вариантов паттерна MVC. Каждый раз, когда я использую это, я формирую это к своим потребностям / настроению. Тем не менее, я стараюсь избегать циклических зависимостей. Я предпочитаю ограничивать зависимости в одном направлении. Или вообще ничего!

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

Некоторые люди делают это наоборот.

Причины, чтобы избежать конкретных зависимостей

  • Сложно поменять один объект на другой - зависимому, вероятно, потребуется модификация или, по крайней мере, перекомпиляция.
  • сложнее в обслуживании - не может изменять компоненты независимо друг от друга
  • сложнее тестировать изолированно - нужно модифицировать и перекомпилировать зависимые для свопинга в фиктивной реализации зависимости
1 голос
/ 03 ноября 2011

Я полностью согласен с @Charles, когда он говорит, что:

слабая связь имеет основополагающее значение для хорошего дизайна.

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

0 голосов
/ 03 ноября 2011

Я не эксперт во всем MVC / MVP, но вот что я делаю большую часть времени.

Для простых приложений, где автоматизация и тестирование пользовательского интерфейса не являются проблемой, я использую графический интерфейс в зависимости от конкретного контроллера (мое представление фактически создает экземпляр контроллера). Однако я должен убедиться, что GUI реализует некоторый интерфейс представления, который контроллер принимает в качестве параметра в своем конструкторе. Таким образом, мне не нужно использовать какое-либо событие или поведение, похожее на наблюдателя: контроллер имеет доступ к интерфейсу представления, и представление содержит контроллер в качестве своего члена. Проблема с этим подходом, на мой взгляд, заключается в том, что он не очень дружественный к тестам. Хотя некоторые могут утверждать, что MVP (Model View Presenter) может быть основан на этом подходе, мне не нравится тот факт, что контроллер не может существовать без создания объекта GUI. Даже если вы передадите контроллер в качестве параметра объекта GUI в его конструкторе, я склонен считать его скорее хаком. Еще одна проблема, связанная с этим подходом, заключается в том, что GUI на самом деле недостаточно пассивно . Мне нравится, что логика в моем пользовательском интерфейсе обрабатывается контроллером, а не наоборот. Но это может быть только личный выбор.

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

Только мои 2 цента ...

...