What's the benefit of factory constructor in MapEntry class?

Viewed 70

Original code for MapEntry

class MapEntry<K, V> {
  final K key;
  final V value;

  const factory MapEntry(K key, V value) = MapEntry<K, V>._;

  const MapEntry._(this.key, this.value);
}

What's the need to create above factory constructor when you can simply have:

class MapEntry<K, V> {
  final K key;
  final V value;

  const MapEntry(this.key, this.value);
}
1 Answers

Writing the constructor like this effectively makes the class final (Classes are unable to extend from this class). Only generative constructors can be used to call super(). This is as opposed to factory constructors which cannot be used in such a way. As the only generative constructor is the private one named _, extension is prevented. There is the caveat that classes in the same package could extend the class as private members are available to classes in the same package.

By having the factory constructor, instances of MapEntry can still be created even though the default constructor is private.

class MapEntry<K, V> {
  final K key;
  final V value;
  const factory MapEntry(K key, V value) = MapEntry<K, V>._;
  const MapEntry._(this.key, this.value);
  
}

class ExtendableMapEntry<K, V> {
  final K key;
  final V value;
  const ExtendableMapEntry(this.key, this.value);  
}


// ---------------

class GoodChild extends ExtendableMapEntry<int, int>{
  GoodChild(int i):super(i,i);
}

// Error:
// The constructor 'MapEntry<int, int> MapEntry(int key, int value)' is a
// factory constructor, but must be a generative constructor to be a valid
// superinitializer - line 24
class ImpossibleChild extends MapEntry<int, int>{
  ImpossibleChild(int i):super(i,i);
}
Related