Как я могу отделить пользовательский интерфейс от бизнес-логики, сохраняя при этом эффективность?

19

Допустим, я хочу показать форму, которая представляет 10 различных объектов в выпадающем списке. Например, я хочу, чтобы пользователь выбрал один гамбургер из 10 разных, содержащих помидоры.

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

Разве это не невероятно неэффективно? У вас уже были объекты, из которых вы хотели выбрать один. Если вы отправили в форму целые объекты, а затем вернули определенный объект, вам не нужно будет повторно указывать его позже, поскольку форма уже вернула ссылку на этот объект.

Более того, если я ошибаюсь и вам действительно нужно отправить весь объект в форму, как я могу изолировать интерфейс от логики?

Uri
источник
Каким образом это будет неэффективно? В любом случае вам нужно показать строковое представление пользователю и сопоставить его ответ с исходным объектом.
Саймон Бергот
Проблема в том, что для работы с указанным объектом мне нужно снова получить его после того, как пользователь выбрал его.
Ури

Ответы:

34

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

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

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

Слабая связь означает, что A знает B, но B не знает A. Другими словами, две вовлеченные стороны играют разные роли клиента и сервера , где клиент знает сервер, но сервер не знает клиента.

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

Чтобы выразить это более практично, нигде в файлах логики исходного кода не должно быть каких-либо операторов include / import / using, которые относятся к файлам пользовательского интерфейса, в то время как файлы исходного кода пользовательского интерфейса будут полны include / import / using заявления, которые относятся к файлам логики.

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

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

Майк Накис
источник
5

Вы должны отделить каждую часть Модели, Представления и Контроллера, но нет никаких причин, по которым вы не можете (например) передавать объекты Модели между Контроллером и Представлением.

Так что в вашем случае Hamburgerобъекты будут частью модели. Затем вы используете свой контроллер для получения необходимого списка Hamburgers и передаете эти объекты в представление (выпадающий список) для отображения. Когда ваш пользователь выбрал, какой гамбургер, вы можете снова передать Hamburgerобъект обратно в контроллер для обработки.

Дело в том, что вы все равно можете тестировать модули Hamburgerлогики «выборки » и логики «процесса Hamburger» отдельно от фактического отображения гамбургеров.

Дин Хардинг
источник
Я понимаю. Однако тогда, если я изменю класс Hamburguer, я должен буду также изменить код формы, который имеет дело с объектами Hamburguer? Где же тогда разделение UI-Logic?
Ури
2
Гамбургер является частью модели. Когда вы модифицируете модель, вы в конечном итоге модифицируете вид и контроллер. Модель представляет собой разделение между пользовательским интерфейсом и логикой. Прикосновение к нему стоит дороже, поэтому вы должны быть осторожны при его разработке.
Саймон Бергот