我正在尝试在我的新项目中使用Model-View-Controller-Pattern,一个Windows Forms C#Application。 我的项目分为几个子项目:
Core
UI (View)
Controller
Model
Services
Helper
Tests
项目依赖如下:
我的UI-Project包含2个表单,ListForm和AddForm(还有其他表单,但这些与此问题无关)。
在Controller-Project中,我有不同表单的接口,Controller用它来更新View。
在Core-Project中,我初始化了一个新的ListForm,Controller和Model。
现在,如果用户单击ListForm中的Add-Button,我希望AddForm显示。 但是如果Controller甚至不知道UI-Project,我如何在Controller中创建一个新的AddForm实例呢?
我尝试使用服务,但由于服务必须知道用于创建实例的UI-Project,因此我会有一个循环依赖(根据Visual Studio)。
如果用户单击ListForm中的Add-Button,如何显示AddForm? (一次显示最多1个AddForm)。
答案 0 :(得分:3)
可能的方法之一涉及控制器工厂。工厂负责创建控制器和视图,并将它们连接在一起。
工厂应该是可配置的,因此您可以针对不同的视图集进行不同的实现 - 用于构建实际ui的一组视图具有其自己的工厂,另一个测试集具有另一个工厂等。所有工厂都通过相同的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() );
通过这种方式,您可以将任何特定的提供程序插入工厂,测试提供程序,ui提供程序等等。实际的实施可能会有所不同,但你应该明白这一点。