5

If I am understanding correctly:

"A factory constructor affords an abstract class to be 
    instantiated by another class, despite being abstract." 

As example:

abstract class Animal {
   String makeNoise(String sound);
   String chooseColor(String color);
   factory Animal() => new Cat(); 
}

class Cat implements Animal {
   String makeNoise(String noise) => noise;
   String chooseColor(color) => color;
}

The above allows me to do this:

Cat cat = new Animal();
var catSound = cat.makeNoise('Meow');
var catColor = cat.chooseColor('black');
print(catSound); // Meow

And it also prevents me from doing this:

class Dog implements Animal {
 int age;
 String makeNoise(String noise) => noise;
 String chooseColor(color) => color;
}

Dog dog = new Animal(); // <-- Not allowed because of the factory constructor

So if I am correct with all this, I am led to ask why the extra code for Animal?

If you intend on using a factory constructor for animal, which creates only cats, why not just have a Cat class with the required methods/properties?

Or, is the purpose of the Animal class with a factory constructor like above, really an interface specifically designed for Cat class only?

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567

3 Answers3

11

I don't think that the problem in the factory.

Your code initially was wrong.

Look at this code and make your conclusions.

Locomotive locomotive = new SomethingWithSmokeFromChimney();

Now look at this code.

Plant plant = new SomethingWithSmokeFromChimney();

You mistakenly believe that all animals on the earth (even the dogs) are cats.

Cat cat = new Animal();

If you want this.

Cat cat = new Animal();
Dog dog = new Animal();

Then (if I correctly understand you) you also want this.

// Cat cat = new Animal();
// Dog dog = new Animal(); 
Dog dog = new Cat();

P.S.

The same wrong conclusions but without factory.

void main() {
  Cat cat = new Animal();
  Dog dog = new Animal();
}

class Animal {
}

class Cat implements Animal {
}

class Dog implements Animal {
}

But this code (depending on documenation) may be considered correct.

void main() {
  Cat cat = new Animal("cat");
  Dog dog = new Animal("dog");
}

abstract class Animal {
  factory Animal(String type) {
    switch(type) {
      case "cat":
        return new Cat();
      case "dog":
        return new Dog();
      default:
        throw "The '$type' is not an animal";
    }
  }
}

class Cat implements Animal {
}

class Dog implements Animal {
}

The factory constructor of the abstract class can return (by default) some default implementation of this abstract class.

abstract class Future<T> {
   factory Future(computation()) {
    _Future result = new _Future<T>();
    Timer.run(() {
      try {
        result._complete(computation());
      } catch (e, s) {
        result._completeError(e, s);
      }
    });
    return result;
  }
}
mezoni
  • 10,684
  • 4
  • 32
  • 54
4

I would see Cat as the default implementation of Animal.

Of course you can't do Dog dog = new Animal(); because new Animal(); returns a Cat but you can do Dog dog = new Dog(); or Animal animal = new Dog();

EDIT to long for a comment
:) This is just one other example how you can utilize factory constructor. Try to see the factory constructor as a normal function (top level function or static class function) that returns an object. To make the user of the class unaware of what is going on behind the scene allow him to use it like a constructor with new SomeClass. That is what a factory constructor is. The first use cases that comes to mind are usually an implementation for the singleton pattern or for caching purposes but also all other cases where it looks for the user of the class as if he just creates a new instance but in fact he gets something constructed and prepared in a way that is more complicated but he needs not to be aware of.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • "I would see Cat as the default implementation of Animal." Then you are telling me Animal was designed specifically for Cat and therefore it is an interface (C# wise) for Cat? –  Mar 16 '14 at 13:10
  • It is an interface that has a constructor that returns its default implementation. It is just for convenience that the interface also provides a function that creates an object that implements this interface. You could drop this factory constructor and just use `Cat cat = new Cat();` for the same result. – Günter Zöchbauer Mar 16 '14 at 13:12
  • I understand that, but I see the factory as an approach designed for no other purpose but creating an interface that can be implemented ONLY by a specific class, ie a custom interface, in this case Cat, if one wants to instantiate an Animal class, but why one would want to do that is beyond me. –  Mar 16 '14 at 13:17
  • It doesn't limit you to implement this interface at all as I showed in my answer and comments. That the interface also has a 'constructor' is just for convenience. This example is by no means the only purpose of the factory constructor https://www.dartlang.org/articles/idiomatic-dart/#factory-constructors – Günter Zöchbauer Mar 16 '14 at 13:22
  • OK, after reading your link, if I understand things, factory prevents 'newing up' a new object. So if I were to create another Cat with the same properties/methods, I would only have 1 cat not 2 cats. –  Mar 16 '14 at 13:24
  • I guess a real world scenario would clear it up for me. Right now I can not see its application in LOB app. –  Mar 16 '14 at 13:38
  • It is just syntactic sugar that allows you to make a constructor do what otherwise only a function could do - that's all. It is only for convenienct, there is no need at all to use it. – Günter Zöchbauer Mar 16 '14 at 13:40
  • I'm trying to implement a class hierarchy wherein the factory in the abstract class returns a subclass instance depending on the parameters passed to it. In my case, the code would be "Animal animal = new Animal('Cat')". The string 'Cat' would be returned from the mirror system or possibly just a String field of the calling class. I haven't figured that one out, yet. But in any case, any implementations in the superclass would operate on its 'animal' attribute. – Tom Russell Oct 28 '15 at 20:23
  • But in any case, any implementations in AnimalHouse would operate on its 'animalType' attribute so that CatHouse::addAnimal() would add a Cat instance (pls forgive the C++ notation). – Tom Russell Oct 28 '15 at 20:33
  • I don't understand your comments. Are they supposed to add further explanation or is it a question? – Günter Zöchbauer Oct 29 '15 at 05:00
2

The one characteristic of a factory constructor is that the object is not already created at the method start. In the method you can have various mechanisms to create the object, like for example:

abstract class Animal {
  String makeNoise(String sound);
  String chooseColor(String color);
  factory Animal() {
    var random = new math.Random();
    if (random.nextBool() == true) 
      return new Cat();
    else
      return new Dog();
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Ozan
  • 4,345
  • 2
  • 23
  • 35