/*
* This example demonstrates the use of interrelated parallel inheritance
* hierarchies: a subclass in one hierarchy (A) contains a reference to
* the base class of another hierarchy (B). When (A) subclass is
* instantiated its reference to (B) is assigned an object of the correct
* subclass of (B).
*
* In this case, when a CatStudio is instantiated, it knows to populate
* its reference to Animal with a Cat.
*
* While it's possible to simply specify the Cat class in CatStudio, this
* would force the AnimalStudio class to know about Cat.
*/
library app.models;
import "dart:mirrors";
class CatStudio extends AnimalStudio {
final animalType = "Cat";
CatStudio() : super();
}
class Cat extends AnimalBase {
Cat() : super("Meow");
}
/* When instantiating a new AnimalStudio subclass in client code, it is
* only necessary to specify animalType as a final String in order to
* get an instance of the desired Animal subclass assigned to the
* `animal` attribute. In turn, AnimalBase is not required to know
* anything about Animal subclasses defined in the client code.
*/
abstract class AnimalStudio {
Animal animal;
final String animalType;
String record() {
print("$animalType: ${animal.sing()}");
}
AnimalStudio() {
animal = new Animal(animalType);
}
}
/* A factory is required here as the calling code (AnimalStudio) knows
* only the name of the Animal subclass to instantiate. Dart's reflection
* system is queried to retrieve, and instantiate, the Animal class
* defined in the client code. The file with client code must contain
* the "library app.models" statement.
*/
abstract class Animal {
final String sound;
String sing() => sound;
factory Animal(String type) {
LibraryMirror lib = currentMirrorSystem().findLibrary(
new Symbol('app.models'));
Map<Symbol, Mirror> classes = lib.declarations;
ClassMirror cls = classes[new Symbol(type)];
InstanceMirror inst = cls.newInstance(new Symbol(''), []);
return inst.reflectee;
}
}
/* This is the class that must be extended in client code when defining
* Animal subclasses. When the `Animal` factory is called with the
* `animalType` parameter, the constructor of the desired subclass is
* called. This will result in the *generative* constructor of the
* superclass being called. This would be `Animal()`, which doesn't
* exist. A workaround for this is presented in various places which
* calls for creating a generative constructor with a mangled name,
* such as `_Animal()`. This is abstruse, however, and the presentation
* herein is considered idiomatic Dart as seen in the standard libraries,
* etc (reference needed).
*/
class AnimalBase implements Animal {
final String sound;
String sing() => sound;
AnimalBase(this.sound);
}
void main() {
new CatStudio().record();
}
Friday, June 17, 2016
Using the factory pattern in a Dart abstract class
Subscribe to:
Posts (Atom)