Как управлять несколькими формами в MVC-Pattern
Я пытаюсь использовать Model-View-Controller-Pattern в моем новом проекте, приложении Windows Forms C#. Мой проект разделен на несколько подпроектов:
Core
UI (View)
Controller
Model
Services
Helper
Tests
Зависимости проекта следующие:
Мой UI-проект содержит 2 формы, ListForm и AddForm (есть другие формы, но они не имеют отношения к этому вопросу).
В Контроллер-Проекте у меня есть интерфейсы для различных форм, которые Контроллер использует для обновления Представления.
В базовом проекте я инициализирую новый ListForm, Controller и Model.
Теперь, если пользователь нажимает кнопку добавления внутри ListForm, я хочу, чтобы AddForm показывал. Но как я могу создать новый экземпляр AddForm внутри Контроллера, если Контроллер даже не знает UI-Project?
Я пытался использовать Сервис, но так как Сервис должен был знать UI-Project для создания экземпляров, у меня была бы круговая зависимость (согласно Visual Studio).
Как я могу показать AddForm, если Пользователи нажимают кнопку Add внутри ListForm? (Всегда отображается максимум 1 AddForm).
1 ответ
Один из возможных подходов связан с фабрикой контроллеров. Фабрика отвечает за создание контроллеров и представлений, а также за соединение проводов.
Фабрика должна быть настраиваемой, чтобы у вас могли быть разные реализации для разных наборов представлений - набор представлений, который используется для создания реального пользовательского интерфейса, имеет свою собственную фабрику, другой набор тестов имеет другую фабрику и т. Д. Все фабрики доступны через один и тот же API. так что вы можете перенастроить фабрику только при необходимости. Одним из возможных способов реализации такой фабрики было бы использование контейнера IoC, это могло бы упростить реализацию, но в этом нет необходимости. С контейнером IoC вы просто регистрируете различные реализации ваших представлений и можете повторно использовать одну и ту же реализацию фабрики, тогда как без контейнера IoC вам потребуется дополнительная реализация фабрики для каждого набора представлений.
Затем ваш родительский контроллер создает экземпляр дочернего контроллера, используя фабрику. Фабрика возвращает дочерний контроллер с соответствующим видом, введенным в него. Родительский контроллер вызывает ShowView
на дочернем контроллере, который просто делает вид видимым, иначе дочерний контроллер может даже автоматически отобразить вид при создании.
Редактировать: пример фабрики, которая создает контроллеры / представления:
На уровне контроллера:
public interface IControllerFactory
{
TController CreateControllerAndView<TController>()
where TController : Controller;
}
public class ControllerFactory
{
// actual provider
private static IControllerFactory _provider;
// factory method
public static TController
CreateControllerAndView<TController>() where T : Controller
{
return _provider.CreateController<TController>();
}
public static void SetProvider( IControllerFactory provider )
{
_provider = provider;
}
}
Каждый раз, когда вы хотите создать новый контроллер, вы обращаетесь к фабрике:
var controller = ControllerFactory.CreateControllerAndView<UserController>();
Обратите внимание, что фабрика ни от чего не зависит, она просто определена, но еще не реализована.
Затем, где-то на самом верхнем уровне, в проекте запуска, возможно, вы реализуете конкретный поставщик:
public class ConcreteControllerFactory : IControllerFactory
{
public TController CreateControllerAndView<TController>()
{
// since you are in the top most layer, you know all types from
// underlaying layers, including controllers and views
// IoC would help here a lot! But without it:
if ( typeof<TController> == typeof<UserController> )
{
IUserView view = new UIUserView();
UserController c = new UserController( view );
}
...
}
}
а потом где-то
ControllerFactory.SetProvider( new ConcreteControllerFactory() );
Таким образом, вы можете подключить к фабрике любого конкретного провайдера, провайдера тестирования, провайдера пользовательского интерфейса и т. Д. Реальная реализация может отличаться, но вы должны понять.