skip to Main Content

I have a class & enum that looks like this

enum UnitsOfMeasurement {
  meters,
  feet,
  inches,
  centimeters,
  millimeters,
}

class MyMaterial {
  final double height;
  final UnitsOfMeasurement unitOfMeasurement;
  MyMaterial({required this.height, required this.unitOfMeasurement});
}

The user can change the unit of measurment and then when I display the height I have utility functions to parse from and to each unit of measurment (from meters to inches, from inches to feet, etc..).

I would like to see if it’s possible to include this logic into the enum, or if there is some other better method than having multiple utility functions to handle this logic.

2

Answers


  1. Add a customized getter method inside the class

    enum UnitsOfMeasurement {
      meters,
      feet,
      inches,
      centimeters,
      millimeters,
    }
    
    class MyMaterial {
      final double height;
      final UnitsOfMeasurement unitOfMeasurement;
      MyMaterial({required this.height, required this.unitOfMeasurement});
      
      double get convertedHeight{
        switch(unitOfMeasurement){
          case UnitsOfMeasurement.meters:  return 1.0; //change the logic;
          case UnitsOfMeasurement.feet:  return 1.0; //change the logic;
          case UnitsOfMeasurement.inches:  return 1.0; //change the logic;
          case UnitsOfMeasurement.centimeters:  return 1.0; //change the logic;
          case UnitsOfMeasurement.millimeters:  return 1.0; //change the logic;
          default:  return 1.0; //change the logic;
        }
      }
    }
    

    now call the convertedHeight like this:

    MyMaterial(height: 10, unitOfMeasurement: UnitsOfMeasurement.inches).convertedHeight;
    
    Login or Signup to reply.
  2. Edit (cred to Randal):

    enum UnitsOfMeasurement {
      meters(1),
      feet(3.28),
      inches(39.3700787402),
      centimeters(100),
      millimeters(1000);
    
      const UnitsOfMeasurement(this.inMeters);
      final double inMeters;
    
      double convert(double value, UnitsOfMeasurement to) => value / inMeters * to.inMeters;
    }
    

    Used as:

    print(UnitsOfMeasurement.inches.convert(42, UnitsOfMeasurement.millimeters));
    

    Or in terms of the MyMaterial class:

    class MyMaterial {
      final double height;
      final UnitsOfMeasurement unitOfMeasurement;
      MyMaterial({required this.height, required this.unitOfMeasurement});
    
      double convert(UnitsOfMeasurement to) => unitOfMeasurement.convert(height, to);
    

    Original answer:

    You don’t need multiple utility functions. One mapping/factor table and one method/function is enough. Place the method and table at a point of your liking.

    There are a few way to do this. I don’t think using enhanced enums is the cleanest approach. I think the cleanest approach is a translation/mapping/factor table and a simple method in the MyMaterial class. This is shown last of the examples.

    Enhanced enum way:

    enum UnitsOfMeasurement {
      meters,
      feet,
      inches,
      centimeters,
      millimeters;
    
      double convert(double value, UnitsOfMeasurement to) => value * factors[this]![to]!;
    }
    

    Extension method on enum way:

    extension UnitsOfMeasurementX on UnitsOfMeasurement {
      double convertX(double value, UnitsOfMeasurement to) {
        return value * factors[this]![to]!;
      }
    }
    

    Simple method on MyMaterial:

    class MyMaterial {
      final double height;
      final UnitsOfMeasurement unitOfMeasurement;
      MyMaterial({required this.height, required this.unitOfMeasurement});
    
      double convert(UnitsOfMeasurement to) => height * factors[unitOfMeasurement]![to]!;
    }
    

    You could obviously use the enhanced enum method, or the extension method inside the MyMaterial class method if you don’t like to have the conversion logic stored in the MyMaterial class. Then you would just do this in the MyMaterial method:

    double convert(UnitsOfMeasurement to) => unitOfMeasurement.convert(height, to);
    

    Mapping/Factor logic:

    All options use a factor mapping that looks like this. Not completed though, that is for the OP to add 🙂 :

    const factors = <UnitsOfMeasurement, Map<UnitsOfMeasurement, double>>{
      UnitsOfMeasurement.meters: {
        UnitsOfMeasurement.meters: 1,
        UnitsOfMeasurement.millimeters: 1000,
        UnitsOfMeasurement.centimeters: 100,
        UnitsOfMeasurement.inches: 39.3700787402,
        UnitsOfMeasurement.feet: 3.28084,
      },
      UnitsOfMeasurement.feet: {
        UnitsOfMeasurement.feet: 1,
        UnitsOfMeasurement.meters: 1 / 3.28084,
      },
      UnitsOfMeasurement.inches: {
        UnitsOfMeasurement.inches: 1,
        UnitsOfMeasurement.meters: 1 / 39.3700787402,
      },
      UnitsOfMeasurement.centimeters: {
        UnitsOfMeasurement.centimeters: 1,
        UnitsOfMeasurement.meters: 1 / 100,
      },
      UnitsOfMeasurement.millimeters: {
        UnitsOfMeasurement.millimeters: 1,
        UnitsOfMeasurement.meters: 1 / 1000,
      },
    };
    

    Used like this:

    void main(List<String> arguments) {
      final material = MyMaterial(
        height: 2,
        unitOfMeasurement: UnitsOfMeasurement.meters,
      );
    
      print(material.convert(UnitsOfMeasurement.feet));
      print(material.unitOfMeasurement.convert(material.height, UnitsOfMeasurement.feet));
      print(material.unitOfMeasurement.convertX(material.height, UnitsOfMeasurement.feet));
    
      final enhancedEnum = UnitsOfMeasurement.meters;
      print(enhancedEnum.convert(2, UnitsOfMeasurement.feet));
    
      final extensionEnum = UnitsOfMeasurement.meters;
      print(extensionEnum.convertX(2, UnitsOfMeasurement.feet));
    }
    

    DartPad with all the code:

    https://dartpad.dev/?id=2f750de1fbc1da5b39555248e24c6c04

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search