0
votes

(Edited a lot) I've got some classes with Abstracts Members. The concrete type of the abstract members is to be determined at the class instanciation, based on the user's input. However, the second member's concrete type might depend on the first member.

I'm trying to do something keeping the MVP design pattern in mind. I taught about making the Presenter pass a delegate to the Model's Ctor, which he (the Ctor) would use to request the informations needed for the instanciation of the class. I'm not sure if it's a good idea. Here is what I wrote :

// In the Model :
public class Model
{
    public E Element1;
    public E Element2;

    public Model(CustomCtor<ModelElement, IModelElement> GetModelElement)
    {
        this.Element1 = (E)GetModelElement(ModelElement.E, null);
        this.Element2 = (E)GetModelElement(ModelElement.E, null);
        //Element2 does not depend on Element1 in this case though.
    }
}

public abstract class E : IModelElement { }

public class EA : E
{
    public string Element1;
    public EA(string Element1) { this.Element1 = Element1; }
}

public class EB : E
{
    public int Element1;
    public EB(int Element1) { this.Element1 = Element1; }
}

public interface IModelElement { }

public enum ModelElement { E, EA, EB }

// In the Presenter :
public class Presenter
{
    View.View view1;

    public Presenter() { }
    public void SetView(View.View view) { this.view1 = view; }

    public Model.Model MakeModel()
    {
        CustomCtor<ModelElement, IModelElement> GetModelElement = new CustomCtor<ModelElement, IModelElement>(GetModelElement<ModelElement, IModelElement>);
        return new Model.Model(GetModelElement);
    }

    private Model.IModelElement GetModelElement<ModelElement, Tout>(Model.ModelElement ME, object obj)
    {
        switch (ME)
        {
            case Model.ModelElement.E:
                return MakeE();
            // One case per Model.ModelElement
            default:
                throw new Exception("ModelElement not implemented in the Presenter.");
        }
        return default(Model.IModelElement);
    }

    private E MakeE()
    {
        switch (view1.AskEType())
        {
            case 1:
                return MakeEA();
            case 2:
                return MakeEB();
            default:
                throw new Exception();
        }
    }

    private EA MakeEA() { return new EA(view1.AskString("EA.Element1 (String)")); }
    private EB MakeEB() { return new EB(view1.AskInt("EB.Element1 (Int)")); }
}

// Shared to the Model and the Presenter :
public delegate TOut CustomCtor<EnumType, TOut>(EnumType Enum, object Params) where EnumType : struct;

// In the View :
public class View
{
    public int AskEType()
    {
        Console.WriteLine(string.Format("Type of E : EA(1) or EB(2)?"));
        return int.Parse(Console.ReadLine());
    }
    public string AskString(string Name)
    {
        Console.Write(string.Format("{0} ? ", Name));
        return Console.ReadLine();
    }
    public int AskInt(string Name)
    {
        Console.Write(string.Format("{0} ? ", Name));
        return int.Parse(Console.ReadLine());
    }
}

//In the Program :
class Program
{
    static void Main(string[] args)
    {
        View.View view1 = new View.View();
        Presenter.Presenter presenter1 = new Presenter.Presenter();

        presenter1.SetView(view1);
        presenter1.MakeModel();
    }
}

Does that make sense? Is there a name for the thing I'm trying to do? (beside "A weird thing") Are you aware of a design pattern I should read on? I taught about mixing the Builder design pattern with the MVP, but I'm not sure how I'd do that.

Thanks

1

1 Answers

1
votes

I am not certain this is what your asking about, but I am assuming you are trying to keep your view isolated from your model. If that is indeed what you are trying to do, I think your taking a much too complicated approach. The view is simply a presentation and feedback medium. It really does not need to know anything about models, it can be designed to make use of simple data in a property bag of some kind. This creates a cleaner separation, however, it often makes rendering data and maintaining the view a lot harder as well.

First question I would ask is, is it REALLY worth it to expend so much effort keeping your view entirely isolated from your model? What are you really gaining by having an absolute separation?

If you do indeed need a separation, make sure you understand the roles of view and presenter. The view is dumb...it knows nothing and does nothing. It presents information and forms. The browser issues commands requested by the user. The presenter handles commands, and directs data to its view. The concept of "presenter asking the view" for anything is generally incorrect. The presenter should be handling the command (http request) directly, so it should know any and all details about a particular command. When it comes time to render the view, the presenter should provide any data to the view in whatever form the view needs it to be in. If you do not want your view to know about your object model, then either create properties on the view itself to contain the data, or create a view-specific model that encapsulates the data required.

EDIT:

I've just read your update. I think I understand your problem a bit better now. First off, before I go any farther, you need to reorganize responsibilities a little bit. Currently, you have it such that your view is responsible for handling input. That is a bit of a corruption of the purpose and concept of a 'view'. In both MVP and MVC, the view is supposed to be as "dumb" as possible, and really should not be responsible for processing anything...commands, actions, input, etc. should all be the responsibility of the Controller or Presenter.

Seeing that your view is actually a console application, not a web forms application (which was my original assumption), I think that MVC might actually be a better fit for your needs. MVP is a good solution for getting around the deficiencies of ASP.NET WebForms, but it is not as powerful or successful at helping separate concerns as MVC is. I would look into implementing an MVC pattern, which was originally designed for console type applications. The controller becomes the central input handler, which then issues commands to command handlers and your model. The view would then be pure and true to form...only rendering information and nothing else.

If there is some reason why you cannot use an MVC approach, which I think would be ideal, and must use MVP, I can offer more advice on how you could fix your current implementation. However, I would strongly suggest looking into using MVC, as that patterns was originally designed to solve the very problem you are trying to solve...in console applications.