dimanche 31 octobre 2021

Design pattern for avoiding triplicate code for dart csv log writer (class properties, csv header, row values)

Firstly I'm fairly new to dart, so I'm not sure how I would even search properly for this, but what I'm trying to do is use the same name for the csv row header, the class properties and then using the properties for the row values.

Is there a sane way to use a single "name", variable or something else to reuse for multiple purposes? The main concern I have with what I'm doing here is that it's overly verbose and means it could be easy to miss a property while developing. It can be assumed that each row will contain all values (null or otherwise) and these will match in order with the respective "header" row and each of these should have a corresponding property in the class.

My current solution is to just define the property, and a method to write a header row and a method to write all the relevant properties to a new row, but it feels like unnecessary code duplication.

My work in progress code is as follows:

class ExperimentLog {
  // top level (experiment)
  String experiment;
  String subject;
  String? condition;
  DateTime? expStartTime;
  DateTime? expEndTime;
  int? expElapsedTimeMs;

  // trial level
  int trial = 0;
  String? cue;

  DateTime? trialStartTime;
  DateTime? trialEndTime;
  int? trialElapsedTimeMs;

  double? xStart;
  double? yStart;
  double? xEnd;
  double? yEnd;
  double? avgVel;

  bool? correct;

  // movement level
  double? xPos;
  double? yPos;
  double? angle;
  double? stepVel;

  // internal
  List<List<dynamic>> _logRows = [];
  Stopwatch expStopWatch = Stopwatch();
  Stopwatch trialStopWatch = Stopwatch();

  ExperimentLog(this.experiment, this.subject,
      {this.condition, DateTime? expStartTime}) {
    this.expStartTime = expStartTime ?? DateTime.now();
    _addHeaderRow();
  }

  void _addHeaderRow() {
    List<dynamic> _logRow = [];
    _logRow.add("experiment");
    _logRow.add("subject");
    _logRow.add("condition");
    _logRow.add("expStartTime");
    _logRow.add("expEndTime");
    _logRow.add("expElapsedTimeMs");

    _logRow.add("trial");
    _logRow.add("trialStartTime");
    _logRow.add("trialEndTime");
    _logRow.add("trialElapsedTimeMs");
    _logRow.add("cue");
    _logRow.add("xStart");
    _logRow.add("yStart");
    _logRow.add("xEnd");
    _logRow.add("yEnd");
    _logRow.add("avgVel");
    _logRow.add("correct");

    _logRow.add("xPos");
    _logRow.add("yPos");
    _logRow.add("angle");
    _logRow.add("stepVel");

    _logRows.add(_logRow);
  }

  void _addRow() {
    List<dynamic> _logRow = [];
    _logRow.add(experiment);
    _logRow.add(subject);
    _logRow.add(condition);
    _logRow.add(expStartTime);
    _logRow.add(expEndTime);
    _logRow.add(expElapsedTimeMs);

    _logRow.add(trial);
    _logRow.add(trialStartTime);
    _logRow.add(trialEndTime);
    _logRow.add(trialElapsedTimeMs);
    _logRow.add(cue);
    _logRow.add(xStart);
    _logRow.add(yStart);
    _logRow.add(xEnd);
    _logRow.add(yEnd);
    _logRow.add(avgVel);
    _logRow.add(correct);

    _logRow.add(xPos);
    _logRow.add(yPos);
    _logRow.add(angle);
    _logRow.add(stepVel);

    _logRows.add(_logRow);
  }

  void startTrial({int? trial}) {
    trialStartTime = DateTime.now();
    trialStopWatch.stop();
    trialStopWatch.reset();
    trialStopWatch.start();

    this.trial = trial ?? this.trial + 1;
  }
}

Aucun commentaire:

Enregistrer un commentaire