Search code examples
c#winformsc#-4.0mvp

MVP, where should the classes be created?


Im having some issues with the MVP pattern, specifically where to create the instances of all my classes. At present these are all created in the program.cs file. Although this works, ive learnt that this is poor design. Id appreciate it if someone could give me some pointers as to how this should be structured.

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);
    }
}

Solution

  • If you wonder "Why is this post so long!?" it's because I'm chatting to Hans and others in the C# hangout and had an idea (I think) of what it was he wanted to learn.


    Hans,

    It is completely doable to use MVP in WinForms, we have it full blown on an old Windows CE 6 device (winform style) app, and even includes a full CQRS cycle. Anyway.

    The stuff I'm about to list isn't necessary for your program, but I think it will be very useful to you as a developer. What you essentially need to learn (in my opinion) is object lifetimes and dependency hierarchies. These things probably have proper names but hopefully that's descriptive enough.

    So, what you are effectively doing when your application starts, is instantiating everything. Although it may be true that your program uses all of those things, does it really need to have them all instantiated in one place like this? If nothing else, it's making this class responsible for far too much. When you run your application, the first thing that you want to do is display a UI I assume. So, ideally, that's all that should be present in this first method.

    I see that you're passing the various objects you've instantiated into the next object in line, which is a good start - it means you basically have your dependency tree already typed out, line by line. However, you will need to rethink the dependencies before being able to continue with this. Basically, what you're aiming for, is what does this class need in order for it to operate. Don't think further than that (i.e So if this class needs X, I'll have to get a Y because X needs that). You just want to find the first layer of dependencies for each of your classes.

    My advice would be to put in a Dependency Container and use Constructor Injection, not unlike you're doing now. Usually, you would start this process by abstracting the actions and properties of an object, from it's actual implementation.

    i.e.

    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
        }
    }
    

    So, at first glance, you might wonder what's the point to all this, surely this just makes your program needlessly complex. Well, the point is to abstract the implementation details from the consumer.

    Instead of aiming for:

    public class MyConsumer
    {
        private readonly TheImplementation myDependency;
    
        public MyConsumer(TheImplementation myDependency)
        {
            this.myDependency = myDependency
        }
    
        public void ExposedMethod()
        {
            this.myDependency.SomeMethod(14)
        }
     }
    

    we aim for consumers only referencing the interface:

    public class MyConsumer
    {
        private readonly IDoStuff myDependency;
    
        public MyConsumer(IDoStuff myDependency)
        {
            this.myDependency = myDependency
        }
    
        public void ExposedMethod()
        {
            this.myDependency.SomeMethod(14)
        }
     }
    

    What this gives you is flexibility! It means you can make changes to the implementation, or even completely swap out the implementation, without having to ever touch the consumers.

    It also lends itself well to Test Driven Design, because you can swap out the implementations of these interfaces for fake versions (called mocks) so that you can test components (consumers) of your application in absolute isolation - faster tests, better tests. No more testing Presenters causing database queries or meaning you have to spin up IIS Express to run your WCF service that some class down the line might need.

    After that, dependency injection becomes incredibly simple. Your application startup becomes the composition root and handles the binding of your real implementations to the interfaces.

    Once the bindings are complete, all the dependency containers I have ever used (Ninject is my personal favourite, closely followed by Unity) were able to detect your dependency tree automatically, and instantiate entire object graphs by simple requesting the root node. Too much talk, too little code =) Here's an example:

    [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>());
    }
    

    I hope this goes some way to helping you? If not, well damn, took ages to write this up... =)