Search code examples
flutterdartrefactoring

Dart: How to factorise function with the different return type


I have a few similar functions in my project that works the same but have different return types. Is it possible for me to factorise them into 1 function to reduce code reducndancy?

Below is my code sample:

class A {
    final String code;
    final String name;
}
class B {
    final String name;
    final String leaveDate;
}
List<A> testFunc(String value, List<A> list) {
  List<A> result = [];

  for (var E in list) {
    if (E.name!.toLowerCase().contains(value)) {
      result.add(E);
    }
  }
  return result;
}
List<B> testFun1(String value, List<B> list) {
  List<B> result = [];

  for (var E in list) {
    if (E.name!.toLowerCase().contains(value)) {
      result.add(E);
    }
  }
  return result;
}

I have tired to pass out List<dynamic> but it does seem working on my project.


Solution

  • Some options:

    • Make A and B both derive from a common base interface that provides a name getter:

      abstract interface class HasName {
        String get name;
      }
      
      class A implements HasName {
        final String code;
      
        @override
        final String name;
      
        A({required this.code, required this.name});
      }
      
      class B implements HasName {
        @override
        final String name;
      
        final String leaveDate;
      
        B({required this.name, required this.leaveDate});
      }
      
      List<T> testFunc<T extends HasName>(String value, List<T> list) {
        List<T> result = [];
      
        for (var e in list) {
          if (e.name.toLowerCase().contains(value)) {
            result.add(e);
          }
        }
        return result;
      }
      
    • Alternatively make your generic function use callback for the getter:

      List<T> testFunc<T>(String value, List<T> list, String Function(T) getName) {
        List<T> result = [];
      
        for (var e in list) {
          if (getName(e).toLowerCase().contains(value)) {
            result.add(e);
          }
        }
        return result;
      }
      

      and then call it with something like testFunc('foo', listOfA, (a) => a.name).

    If you want to give up static type safety and to use duck-typing instead, you can treat List elements as dynamic:

    List<T> testFunc<T>(String value, List<T> list) {
      List<T> result = [];
    
      for (var e in list) {
        if ((e as dynamic).name.toLowerCase().contains(value)) {
          result.add(e);
        }
      }
      return result;
    }