Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm trying to lead a charge for re factoring our rather bloated controllers. We currently have a BaseModel from which all our other models inherit. The BaseModel contains things common to all pages, such as the page title, css files needed, current user.

Each constructor has a private method to construct a particular ViewModel (essentially a factory method)

BaseModel.cs

Class BaseModel {
    public string title {get; set;}
    public List<String> cssFiles {get;set;}
    // More Properties
}

HomeModel.cs

Class HomeModel : BaseModel {
    public List<News> LatestNews {get;set;}
}

ExtendedHomeModel.cs

Class ExtendedHomeModel : HomeModel {
    public List<RSSItem> Twitter {get;set;}
}

HomeController.cs

public ActionResult Index(int userid) {
    return View(MakeExtendedHomeModel(userid));
}

private ExtendedHomeModel MakeExtendedHomeModel(int userid) {
    var model = new ExtendedHomeModel();

    InitialiseBaseModel(model, userid);
    InitialiseExtendedBaseModel(model);

    model.Twitter = DomainModel.Twitter.GetLatestItems();
}

private HomeModel MakeHomeModel() {
    var model = new HomeModel();
    InitialiseBaseModel(model);
    InitialiseHomeModel(model);
}

private void InitialiseHomeModel(HomeModel model) {
    model.LatestItems = DomainModel.GetLatestItems;
}

private void InitialiseBaseModel(BaseModel model, int userid) {
    model.PageTitle = "Home"
    model.UserId = userid
}

So, my question is: what is the best way of initialising these kind of base models? As far as I can tell what the constructor essentially does is the factory method, and at the very least it should be moved out of the constructor.

However, I'm convinced there is a more elegant way of doing this. The main problem that I see is that the code is thoroughly depended on you calling the initialise methods in the correct order. One idea I've had is to use constructors, passing necessary parameters down the chain as necessary. Are there any pitfalls to this approach I havent seen? (Bearing in mind I've only started asp mvc six months ago). Are there any better ways?

Thanks for reading

share|improve this question

1 Answer 1

up vote 3 down vote accepted

The pattern I have settled on for creating my view models is SomeViewModel is created by a static method (or instance method if appropriate) on SomeViewModelFactory. I don't inherit from base models for members that are duplicated. I use interfaces and external setter methods that operate on those interfaces to set the properties. This abstracts away the creation of the view model to a single function call for a single view model and one setter function called internally for each interface the view model implements. As you can tell, I prefer composition over inheritance in this case. To me, it is less complex and more reusable than inheritance.

You might be interested in Automapper if you are doing any mapping between your domain model for your database and your view models. Hope this helps spur on any ideas that may be laying dormant in your mind.

Edit: I forgot to mention that you can define extension methods on those interfaces to take inputs and do the setting on the object its self. This technique is called a "mixin". That way you don't need to create classes for your setter methods, they appear to you as instance methods on the viewmodel object.

Edit 2: To answer your first comment, that is up to you and your preferences. Personally, I like to stay consistent and I would just copy/paste the model into a new class and add the property. Then use the setter for the old class and just set that one property normally. Remember that there should be no logic in your view models; they should only know that they are holding data, not how that data is created.

Automapper is still being actively developed as far as I can tell. It's really more of a utility library rather than a full blown framework. It seems to be pretty mature to me, I've been using it at work with much success. You may have to write the code that goes from ViewModel to DomainModel for stuff like updating data in a database, but at least you won't have to do the DomainModel > ViewModel part. Automapper takes care of that very well.

Edit 3: Your concern about staying DRY is valid; however, I interpret that principle as don't repeat your logic (not data structure). Your view model is a support structure for your data that provides you the benefit of static typing in your view. Each view model is specific to a single view. Using inheritance for property reuse needlessly ties the view model of 2 separate views that just happen to be similar. If you use inheritance, changing the base view model has a ripple effect across all your views with view models that inherit from it. Maybe that is what you want, but you can get the same benefit by defining an interface for all view models that need it. If there is a change, this allows you to decide for each model if it should still implement that interface or if a new interface is needed.

share|improve this answer
    
Thanks for the input - one question. What do you do if (for arguments sake :-) ) you had two models that were identical, except one model had an extra property... Would you reuse the same model, with a redundant property for a view, or would you copy and paste? Im trying to be aware of DRY, although I dont have much experience in applying it. I guess this is why I don't like the repeated function calls to setters - the compiler does this for you with inheritance –  berkeleybross Jan 3 '13 at 6:41
    
Also, I hadnt heard of Automapper before but it looks quite useful. Do you know what the support/community is like? The last commit was 3 months ago which seems a bit long if I were to try and convince the boss.. –  berkeleybross Jan 3 '13 at 6:44
    
Thanks for the help! Much appreciated –  berkeleybross Jan 3 '13 at 20:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.