Search code examples
dartdart-null-safety

Dart get class property value dynamically


I have a Class YearlyReportArchive, I want to be able to read the value of a single month dynamically and also add all the months and return the sum.

Is there a better solution than what I came up with?

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:mbpt/utils/tools/validate_double.dart';

class YearlyReportArchive {
  final double jan;
  final double feb;
  final double mar;
  final double apr;
  final double may;
  final double jun;
  final double jul;
  final double aug;
  final double sep;
  final double oct;
  final double nov;
  final double dec;

  YearlyReportArchive(
      {required this.jan,
      required this.feb,
      required this.mar,
      required this.apr,
      required this.may,
      required this.jun,
      required this.jul,
      required this.aug,
      required this.sep,
      required this.oct,
      required this.nov,
      required this.dec});

  double monthlyTotal(String monthName) {
    switch (monthName) {
      case 'jan':
        return jan;
      case 'feb':
        return feb;
      case 'mar':
        return mar;
//...
      default:
        return 0.00;
    }
  }

  double yearlyTotal() {
    return jan +
        feb +
        mar +
        apr +
        may +
        jun +
        jul +
        aug +
        oct +
        sep +
        nov +
        dec;
  }

  factory YearlyReportArchive.fromDoc(DocumentSnapshot doc) {
    Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
    return YearlyReportArchive(
        jan: validateDouble(data['jan']),
        feb: validateDouble(data['feb']),
        mar: validateDouble(data['mar']),
        apr: validateDouble(data['apr']),
        may: validateDouble(data['may']),
        jun: validateDouble(data['jun']),
        jul: validateDouble(data['jul']),
        aug: validateDouble(data['aug']),
        sep: validateDouble(data['sep']),
        oct: validateDouble(data['oct']),
        nov: validateDouble(data['nov']),
        dec: validateDouble(data['dec']));
  }
}

Solution

  • First you can create an enumerated type to support your months:

    enum Months {
      january, february, march, april //...// , december
    }
    

    These months have a string representation (e.g. jan). To represent them, you can create a constant map, or a extension on your enumerated type:

    • Creating a constant map:
    Map<Months, String> monthStrings = {
     Months.january: "jan",
     Months.february: "feb",
     Months.march: "mar",
     Months.april: "apr"
    };
    
    extension monthName on Months {
    
      String get name {
        switch (this) {
          case Months.january:
            return 'jan';
          case Months.February:
            return 'feb';
          default:
            return "";
        }
      }
    }
    
    

    This way you can access these values on your class, for example:

    • On your doubles, you can have a single map that associates each month with it's value:
    class YearlyReportArchive {
    Map<Months, double> values;
    }
    
    • Whenever you need to sum all you can use a for:
    double answer = 0;
     for (double value in values.values){
       answer += value;
     }
    
    • When you need the string representation, access the Map you made or the extension method:
    print(monthStrings[Months.january]);
    var m = Months.january;
    print(m.name());
    

    You could also create a class that holds all these methods and definitions, but the general concept would be the same.