Search code examples
interfacedartabstract-class

How to extend an abstract class with factory constructor?


The situation is following:

abstract class A {
  void doSomething() => print('Do something..');
}

class B implements A {
  @override
  void doSomething() => print('Do something already..');
}

class C extends A {
}

I have an abstract class A. Class B implements A. Therefore it overrides doSomething() method. Class C extends A.

Everything works fine, until I'm adding factory constructor to class A:

abstract class A {
  factory A() => new B();

  void doSomething() => print('Do something..');
}

This leads to an error in my IDE (IntelliJ IDEA):

The generative constructor expected, but factory found

My first idea was to create constructor for class C where I would call factory constructor for A. Is it possible to do?

I got the same problem when I try to extend Exception class. It also has a factory constructor:

abstract class Exception {
  factory Exception([var message]) => new _ExceptionImplementation(message);
}

Thats why to create my custom exception I have to implement Exception class instead of extending it and it really confuses me.

I also would like to clarify one terminology question. Can I say that from point of view of B class, A is an interface, so B is implementing interface A. However, from point of view of C class, A is an abstract class so C is extending abstract class A. Are these statements correct?

Thank you.

Dmitry.


Solution

  • If a class has no constructor a generative constructor is implicitly added. If a class has an explicit constructor no generative constructor is added. You have two options.

    • make the factory constructor a named factory constructor and add a normal constructor
    abstract class A {
      void doSomething() => print('Do something..');
      factory A.name() => new B();
      A();
    }
    
    • or make the normal constructor named and call it explicitly from the extending class
    abstract class A {
      void doSomething() => print('Do something..');
      factory A() => new B();
      A.protected();
    }
    
    class C extends A {
      C() : super.protected();
    }
    

    try at DartPad

    Your statement is right. If you implement a class it acts as an interface and if you extend it it acts as a base class.