c# - MVP,类应该在哪里创建?

标签 c# winforms c#-4.0 mvp

我对 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/

相关文章:

c# - 在 foreach 循环中创建多个 DropDownListFor

c# - 将数组中的一个数字与同一数组中的其他数字进行比较

winforms - 防止只读的RichTextBox闪烁光标(IBeam)

c# - 是否有可能将马尔可夫链引导至某些关键字?

.net - Visual Studio Community 2019 不显示设计器 View

c# - 对象数据绑定(bind) c# winforms 不工作

c#-4.0 - Xamarin.Forms 中的互联网连接监听器

multithreading - 如何使用CRM Online 2015实现良好的导入性能

c# - 将字符串列表加入逗号分隔并用单引号括起来

C#(或任何语言)DDD - 在哪里清理用户输入数据?