我在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周期。无论如何。
我要列出的内容对于您的程序不是必需的,但是我认为对于开发人员来说,这将非常有用。 (我认为)您本质上需要学习的是对象生存期和依赖关系层次结构。这些东西可能有适当的名称,但希望它们具有足够的描述性。
因此,在应用程序启动时有效的工作就是实例化所有内容。尽管您的程序可能确实使用了所有这些内容,但是否真的需要将所有这些都实例化在一个地方?如果没有别的,那么这会使这个类承担太多责任。在运行应用程序时,您要做的第一件事是显示一个我假定的UI。因此,理想情况下,这就是第一种方法中应该包含的全部内容。
我看到您正在将实例化的各种对象传递给下一个对象,这是一个好的开始-这意味着您基本上已经逐行输入了依赖树。但是,您将需要重新考虑依赖关系,然后才能继续执行此操作。基本上,您要针对的是此类需要什么才能使其运行。不要再想那么多了(也就是说,如果此类需要X,我将必须获得一个Y,因为X需要它)。您只想找到每个类的依赖关系的第一层。
我的建议是将一个依赖性容器放入并使用构造函数注入,这与您现在所做的没什么不同。通常,您将通过从对象的实际实现中抽象出对象的动作和属性来开始此过程。
即
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)
}
}
这给您带来了灵活性!这意味着您可以更改实现,甚至完全交换实现,而无需接触使用者。
它也很适合测试驱动设计,因为您可以将这些接口的实现换成虚假版本(称为模拟),以便可以绝对隔离地测试应用程序的组件(用户)-更快的测试,更好的测试。无需进行更多测试演示者即可引起数据库查询,或意味着您必须启动IIS Express才能运行某些类可能需要的WCF服务。
之后,依赖注入变得异常简单。您的应用程序启动将成为composition root,并处理您的实际实现与接口的绑定。
绑定完成后,我曾经使用过的所有依赖项容器(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/