How do you implement the strategy pattern using Flutter and Riverpod?

134 Views Asked by At

In my Flutter app, there is a page that loads the data for a given topic. Included in this topic is an identifier for the algorithm to use when the user interacts with the widget. Due to the nature of the app, I could see the number of possible algorithms for many different topics getting bigger over time. The algorithms themselves will be coded into the app, and I would just need to choose which one depending on the identifier present in the Topic model. This seems to be a perfect situation to use the strategy pattern.

In an effort to make this piece of the app as maintainable as possible, I would like to find a good way to register the algorithms so that they can be used at runtime once the data loads. I am using the Riverpod library in my app already, and it would make sense to me to have some providers like this:

abstract interface class TestAlgorithm {
  String foo();
}

@riverpod
class AlgorithmMap extends _$AlgorithmMap {
  @override
  Map<String, TestAlgorithm> build() {
    return {}; // Populate this somehow
  }

  // Possibly like this?
  void registerAlgorithm(String algorithmKey, TestAlgorithm algorithm) {
    final nextState = {
      ...state
    };

    nextState[algorithmKey] = algorithm;
    state = nextState;
  }
}

@riverpod
TestAlgorithm? algorithm(AlgorithmRef ref, String algorithmKey) {
  final algorithmMap = ref.watch(algorithmMapProvider);
  return algorithmMap[algorithmKey];
}

In this case, the widget would be able to watch the algorithmProvider and then run the foo function on the returned algorithm to get the desired results. My problem is, how do I register the providers?

Here are a couple ideas I have had while searching online and thinking through the problem:

  • In the AlgorithmMap provider, build the map manually. This is a very straightforward and simple approach, but every time I add a new algorithm I will need to open up the provider and change it. This would violate the Open/Closed principle.
  • Add a custom annotation, and use the dart:mirrors library to search through the code and register any classes with that annotation as TestAlgorithms. This has the advantage of being able to dynamically build the list of algorithms without me needing to modify the provider again, but it comes with a cost of performance and possibly bloat of the compiled app.

I have also wondered if there is some way I could write a generator that could build the registration code for me based off of an annotation, so I would just have to run that in order to get an updated list whenever I add a new algorithm. That would seem to have the benefits of the two above approaches, while avoiding the downsides of both. Is there a way to do this with generators? Or is there a another approach that would not involve either of these?

0

There are 0 best solutions below