0

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']));
  }
}
Trax
  • 1,445
  • 5
  • 19
  • 39
  • "Better" is subjective. The way you did it is the straightforward way to do it and it works. People might have opinions on how to improve the organization or structure, but I see no compelling reason to make this problem more complicated than it needs to be. – Abion47 Nov 05 '21 at 14:57
  • I'm working on my first project in flutter/dart so I'd like to avoid any big mistakes and learn to do things the proper way. – Trax Nov 05 '21 at 15:08
  • 1
    There is no one proper way. Ask ten different senior developers and you will get ten different answers. The best advice is to follow SOLID principles whenever possible (emphasis on "whenever possible"), don't make things more complicated than they need to be, and to accept that mistakes are inevitable. The only ones to be concerned about is whether you are neglecting a language feature that would make your life easier, and the only one I would suggest here is you could use an `enum` instead of a string for `monthlyTotal`, but that's hardly a significant change. – Abion47 Nov 05 '21 at 15:19
  • Coming from a Typescript and Javascript world, it's a little disappointing and surprising to see why accessing properties on an instantiated object is not supported. Apparently, the only solution is to write lengths of switch cases :| I Wish dart supported accessing props using dynamic strings as names. – Param Singh Jun 04 '23 at 18:58

1 Answers1

1

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.

Naslausky
  • 3,443
  • 1
  • 14
  • 24
  • What purpose does the string map serve when you could just as easily get data from the report class using the enums themselves? – Abion47 Nov 05 '21 at 14:58