Wednesday, January 25, 2012

Singletons via Factories in Dart

‹prev | My Chain | next›

Coding for the web on the ipad has not been working well for me over these past few nights. So tonight, I switch gears and explore me some Dart internals. Specifically, I am going to play with factory constructors.

By declaring an otherwise normal constructor as a factory, we are telling Dart that it need not create instances of the Class under construction. Rather, we will handle it ourselves.

My limited brain has fixated on the most obvious use-case in the world: a singleton. In a sign of just how sleep deprived I am, I will create a class named Foo with a property of bar. If I create two instances of the singleton Foo, then both should have the same value for bar.

In other words, both of the following statements should have the same value for bar:
main() {
  final foo1 = new Foo("bar1")
      , foo2 = new Foo("bar2");

  print("foo1 is: ${foo1.bar}");
  print("foo2 is: ${foo2.bar}");
}
If I implement the Foo class correctly, then the output should be:
foo1 is: bar2
foo2 is: bar2
So let's take a look at the factory constructor for this beast:
class Foo {
  var bar;
  static Foo instance;

  factory Foo(name) {
    if (instance == null) {
      instance = new Foo._internal(name);
    }
    return instance;
  }

  Foo._internal(this.bar);
}
Starting from the bottom, the Foo._internal(this.bar) line is a constructor. The underscore in the name is a convention for a private constructor. By using this.bar as the argument in the constructor, I am saying that any arguments supplied should be used to set the this.bar property.

That is, the following:
var internal = new Foo._internal("internal");
print("internal is: ${internal.bar}");
Should produce:
internal is: internal
Moving up in the class, the factory is defined as:
  factory Foo(name) {
    if (instance == null) {
      instance = new Foo._internal(name);
    }
    return instance;
  }
Just as with my internal construtor, I accept a single argument which will be used to set the bar property. If the static/class property instance is null, then I create it fresh from the internal constructor. If instance has already been set (e.g. a previous object has already defined this static/class variable, then I do nothing. In either case, I return the instance. It is this return value, not internal Dart magic which creates the object instance for factories.

When I run the following:
main() {
  final bar1 = new Foo("bar1")
      , bar2 = new Foo("bar2");

  print("bar1 is: ${bar1.bar}");
  print("bar2 is: ${bar2.bar}");
}
I get the following output:
bar1 is: bar1
bar2 is: bar1
So indeed, I do have my Singleton factory working as desired. Nice.

Day #276

No comments:

Post a Comment