我对 MVP 模式有一些问题,特别是在哪里创建我所有类的实例。目前这些都是在program.cs文件中创建的。虽然这可行,但我了解到这是一个糟糕的设计。如果有人能给我一些关于如何构建它的指示,我将不胜感激。
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var browser = new BrowserWindow();
var helper = new MainPresenterHelper();
var userInterface = new MainForm();
var entity = new UserInputEntity();
var readerWriter = new ReaderWriter();
var manager = new IOManager(readerWriter);
var verif = new VerificationManager(manager);
var entityVerification = new EntityVerification(verif);
var logger = new Logger(entity, readerWriter, true);
var verifyRow = new VerifyRow(entity, logger);
var verification = new VerificationOfDataTypes(entity, logger, verifyRow, new Status(), readerWriter);
var verify = new CsvFileVerification(entityVerification, verification, logger);
var cts = new CancellationTokenSource();
var source = new CancellationTokenSourceWrapper(cts);
var presenter = new MainPresenter(userInterface, browser, helper, entity, verify, source);
Application.Run(userInterface);
}
}
最佳答案
如果您想知道“为什么这篇文章这么长!?”这是因为我在 C# 聚会中与 Hans 和其他人聊天,并且(我认为)知道他想学什么。
<小时/>汉斯,
在 WinForms 中使用 MVP 是完全可行的,我们在旧的 Windows CE 6 设备(winform 风格)应用程序上充分发挥了它的作用,甚至包括完整的 CQRS 周期。无论如何。
我即将列出的内容对于您的程序来说并不是必需的,但我认为它对您作为开发人员非常有用。 (在我看来)你本质上需要学习的是对象生命周期和依赖层次结构。这些东西可能有正确的名称,但希望这具有足够的描述性。
因此,当应用程序启动时,您实际上正在做的就是实例化所有内容。尽管您的程序可能确实使用了所有这些东西,但它真的需要将它们全部实例化在一个地方吗?如果不出意外的话,这会让这个类(class)承担太多的责任。当您运行应用程序时,您要做的第一件事就是显示我假设的 UI。因此,理想情况下,这就是第一个方法中应该存在的全部内容。
我看到您正在将实例化的各种对象传递到行中的下一个对象中,这是一个好的开始 - 这意味着您基本上已经逐行输入了依赖关系树。但是,您需要重新考虑依赖关系,然后才能继续此操作。基本上,您的目标是这个类需要什么才能运行。不要想得更远(也就是说,如果这个类需要 X,我就必须得到 Y,因为 X 需要它)。您只想找到每个类的第一层依赖关系。
我的建议是放入依赖容器并使用构造函数注入(inject),就像您现在所做的那样。通常,您可以通过从对象的实际实现中抽象其操作和属性来开始此过程。
即
public interface IDoStuff
{
string AProperty { get; set; }
bool SomeMethod(int anArgument);
}
public class TheImplementation : IDoStuff
{
public string AProperty { get; set; }
public bool SomeMethod(int anArgument)
{
return false;
}
public void AnotherMethod()
{
this.AProperty = string.Empty
}
}
所以,乍一看,您可能想知道这一切的意义是什么,这肯定会让您的程序变得不必要的复杂。嗯,重点是从消费者那里抽象出实现细节。
而不是瞄准:
public class MyConsumer
{
private readonly TheImplementation myDependency;
public MyConsumer(TheImplementation myDependency)
{
this.myDependency = myDependency
}
public void ExposedMethod()
{
this.myDependency.SomeMethod(14)
}
}
我们的目标是让消费者只引用界面:
public class MyConsumer
{
private readonly IDoStuff myDependency;
public MyConsumer(IDoStuff myDependency)
{
this.myDependency = myDependency
}
public void ExposedMethod()
{
this.myDependency.SomeMethod(14)
}
}
这给您带来的是灵 active !这意味着您可以更改实现,甚至完全替换实现,而无需接触消费者。
它也非常适合测试驱动设计,因为您可以将这些接口(interface)的实现替换为假版本(称为模拟),以便您可以在以下环境中测试应用程序的组件(使用者)绝对隔离 - 更快的测试,更好的测试。不再测试 Presenter 会导致数据库查询,或者意味着您必须启动 IIS Express 来运行某些类可能需要的 WCF 服务。
之后,依赖注入(inject)变得异常简单。您的应用程序启动变为 composition root并处理实际实现与接口(interface)的绑定(bind)。
一旦绑定(bind)完成,我用过的所有依赖容器(Ninject 是我个人最喜欢的,紧随其后的是 Unity)都能够自动检测您的依赖树,并通过简单的请求根节点来实例化整个对象图。废话太多,代码太少 =) 这是一个例子:
[STAThread]
private static void Main()
{
// assuming ninject
IKernel kernel = new StandardKernel();
// some people hate self binds, but you may find this easier than
// creating interfaces for all your existing classes
kernel.Bind<BrowserWindow>().ToSelf();
kernel.Bind<MainPresenterHelper>().ToSelf();
kernel.Bind<MainForm>().ToSelf();
kernel.Bind<UserInputEntity>().ToSelf();
// this is where we use the splitting implementation from interface
kernel.Bind<IReaderWriter>().To<ReaderWriter>();
kernel.Bind<IIOManager>().To<IOManager>();
kernel.Bind<IVerificationManager>().To<VerificationManager>();
// .... etc
//If you do them all correctly, you can simply have the following line
Application.Run(kernel.Get<MainForm>());
}
希望这对您有帮助?如果没有,该死,花了很长时间才写下来......=)
关于c# - MVP,类应该在哪里创建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12836446/