简体   繁体   中英

Base class (Domain Model) conversion to derived class (View Model)

I see the following pattern in an MVC app where basically a derived class has added minor functionality to a domain class, many times just display readonly properties that are dependent on other properties from base class. What would be the better way to not have to write the very basic properties copy code ( between //***** //***** )?

//Can't change this class, it has what is shown (it contains only properties)
public class MyDomainModel
{
    public bool BoolValue { get; set; }

    public string Prop1 { get; set; }
    public int Prop2 { get; set; }
    // Several other properties
}

public class MyViewModel : MyDomainModel
{
    // This is the only property that is added to the view model class
    public string DisplayValue
    {
        get { return BoolValue ? "Value1" : "Value2"; }
    }

    public static MyViewModel FromBase(MyDomainModel myDomainModel)
    {
        var myViewModel = new MyViewModel();

        //*****
        myViewModel.BoolValue = myDomainModel.BoolValue;
        myViewModel.Prop1 = myDomainModel.Prop1;
        myViewModel.Prop2 = myDomainModel.Prop2;
        // Several other properties
        //*****

        return myViewModel;
    }
}

// some other place

MyDomainModel myDomainObject = CallService();

//Here MyDomainModel needs to be converted to MyViewModel
MyViewModel myViewObject = MyViewModel.FromBase(myDomainObject);

EDIT: I wanted this question to address the concern of too much "attribute copying" code spread across the application. Unfortunately, the wrong choice of example (ViewModel derived from DomainModel) led the discussion in another territory.

 public class MyDomainModel { // ..... } public class MyViewModel : MyDomainModel { // ..... } 

Why would you have your View Model inherit your Domain Model? This seems like a terrible idea.

What benefit does inheritance give you in this situation? What are you re-using?

All I can see is a bag of properties, and in your usage scenario you can't even reuse those (since you get an already instantiated base class and you cannot change the instantiation of that to a derived class).

An axiom that seems appropriate here (and often) is "favor composition over inheritance". Unless you have a clear reason and benefit to inheritance, avoid it.

The most common advice is to make your ViewModels completely separate classes and keep them dependency free. They should be simple POCO's.

Then, you simply map your domain model object to your view model object. This will involve some repetitive property copying code or use of a tool like AutoMapper, but you want the duplication here as it reduces coupling.

Inheriting, on the other hand, introduces some terribly tight coupling that will almost certainly cause you problems.

Create a copy-constructor in the base.

That will save you a lot of code in the derived classes.

public class MyDomainModel
{
    public bool BoolValue { get; set; }

    public string Prop1 { get; set; }
    public int Prop2 { get; set; }

    public MyDomainModel(MyDomainModel myDomainModel)
    {
        var myViewModel = new MyViewModel();

        //*****
        this.BoolValue = myDomainModel.BoolValue;
        this.Prop1 = myDomainModel.Prop1;
        this.Prop2 = myDomainModel.Prop2;
        // Several other properties
        //*****
    }
}

public class MyViewModel : MyDomainModel
{
    // This is the only property that is added to the view model class
    public string DisplayValue
    {
        get { return BoolValue ? "Value1" : "Value2"; }
    }

    public MyViewModel (MyDomainModel other) : base(other) {}
}

Then in the code use:

// some other place

MyDomainModel myDomainObject = CallService();

//Here MyDomainModel needs to be converted to MyViewModel
MyViewModel myViewObject = new MyViewModel(myDomainObject);

This looks similar to a pattern where you want to attach information to all models before rendering the view. You can actually do this by overriding OnActionExecuted and then attaching data to your model.

 protected override OnActionExecuted(ActionExecutedContext context)
 {
      ViewResult viewResult = filterContext.Result as ViewResult;

      if(viewResult != null)
      {
           MyDomainModel model = viewResult.ViewData.Model as MyDomainModel;

           if(model != null)
              /* Set Properties on your Model, for any model deriving 
                 from MyDomainModel! */
      }
 } 

I think you are violate Single Responsibility Principle because the Responsibility to ViewModel is just to present the some data from domain model for view without any business logic in this classes view model classes usually represents a DTO object and you can map the data for Domain object into ViewModel object use the AutoMapper

look at the following articles examples Automaper NerdDinner

AutoMapper: the Object-Object Mapper

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM