cs0815
cs0815

Reputation: 17388

Transforming/Mapping models

I have a generic model which is used to store all the data using an ORM technology. This model has to be occasionally transformed into another model to ‘do something’. At the moment I am using this (simplified) approach where the generic model stores weight in kilogram and the target model stores it in pounds:

public class GenericModelClassA
{
    public virtual double Weight { get; set; } 
}

public interface IModelX
{
    double Weight { get; set; }
}

public class ModelXClassA : GenericModelClassA, IModelX
{
    private const double WeightConversionFactor = 2.20462;

    public override double Weight
    {
        set
        {
        base.Weight = value / WeightConversionFactor;
        }
        get
        {
        return base.Weight * WeightConversionFactor;
        }
    }
}

Is this a decent approach to the problem? I have heard about model driven transformation (MDT) languages to query/view/transform/operational (QVTO). Is my approach too naive? Would you recommend MDT languages? Any feedback/opinions would be very much appreciated.

Many thanks.

Christian

Upvotes: 0

Views: 1199

Answers (2)

Andrés Fortier
Andrés Fortier

Reputation: 1693

From the OO point of view there are some concepts that are not explicitly model that may help in this situation. In this case you are representing and absolute amount and its unit of measure with a number (to which you can't delegate any responsibility, since it is not an object) and absorbing that conversion responsibility in your model object. In my opinion you should create a richer model that represents the situation:

  • Class WeightUnit, with subclasses Kilo and Pound.
  • Class Weight, that has an absolute number and a weight unit. In other words, a "weight" is a value plus the unit of weight that gives meaning to that value.
  • Your model class has a weight variable.

I'm not familiar with C# so please bear with me here:

abstract public class WeightUnit
{
    abstract public function convertValueToKilo(float value);
    abstract public function convertValueToPounds(float value);
}

public class Kilo extends WeightUnit
{
    public function convertValueToKilo(float value) {return value;}
    public function convertValueToPounds(float value) {return value * 2.20462262;}
}

public class Pounds extends WeightUnit
{
    public function convertValueToKilo(float value) {return value / 2.20462262;}
    public function convertValueToPounds(float value) {return value;}
}

public class Weight
{
    protected WeightUnit unit;
    protected float value;

    public function Weight(float value, WeightUnit unit)
    {
      //set the internal state
    }

    public function toKilo()
    {
       return new Weight(this.unit.convertValueToKilo(this.value), new Kilo());
    }

    public function toPounds()
    {
       return new Weight(this.unit.convertValueToPounds(this.value), new Pounds());
    }
}

One of the issues with this implementation is that the amount of conversions explodes as more weigh unit you have. For those cases you generally select a "default" unit (e.g. Kilo) and all the other units know how to convert to/from kilo. In that case adding a new unit means adding one class and two methods. However some round errors may arise from doing this double conversion.

HTH

Upvotes: 1

MikeSW
MikeSW

Reputation: 16348

This is how I'd do it.

Domain

public class Weight
{
   public Weight(decimal miligrams) { InMiligrams= miligrams;}

   public decimal InMiligrams {get;private set;}

   public decimal InGrams { get { return InMiligrams*1000; }}

   /* other conversions as properties */
}

Persistence

 public class StorageModel
 {
     public virtual decimal Weight {get;set;}
 }

Mapping

Domain -> Persistence

storage.Weight = weight.InMiligrams;

Persistence -> Domain

weight = new Weight(storage.Weight);

The Persistence layer and the Domain layer know that internally all weights are expressed in miligrams (or whatever other unit of measure you want).

Upvotes: 1

Related Questions