Tuesday, February 9, 2016

A Nearly Modern Factory Method Pattern


I could make do with the examples of the factory method pattern that I have been using. Still, I would prefer an example that touches the modern web a little closer. Or at least the web. So tonight I try my hand at a venerable, if simple, form builder.

I am not going to worry too much about the details of adding different types of HTML form inputs at this point. To kick things off, I start by adding variations of text input fields to a container. So my Dart abstract creator class declares that it needs to be constructed with a container element:
abstract class FormBuilder {
  Element container;
  FormBuilder(this.container);
}
Next, I declare an addInput() method that will append an input field to the container:
abstract class FormBuilder {
  // ...
  void addInput() {
    var input = _labelFor(inputElement);
    container.append(input);
  }
  // ...
}
The _labelFor() helper method is unimportant in this discussion. It merely adds a text label to the input element. What is important here is the inputElement property. That is going to be the factory method in the factory method pattern. It lacks the usual trailing parentheses because it will be a getter method:
abstract class FormBuilder {
  // ...
  InputElement get inputElement;
  // ...
}
It lacks a method body because the definition of what inputElement does will have to come from subclasses.

Putting these all together, I have a prototypical "creator" in the factory method pattern:
abstract class FormBuilder {
  Element container;
  FormBuilder(this.container);
  void addInput() {
    var input = _labelFor(inputElement);
    container.append(input);
  }
  InputElement get inputElement;
  // ...
}
It declares a factory method, inputElement, and an operation that uses that factory, addInput(). The creator in the classic factory method pattern is an interface for concrete implementations.

For a first pass at a concrete creator class, I declare a RandomBuilder class. As the name implies, the inputElement factory method randomly chooses from a selection of input element types:
import 'dart:math' show Random;

class RandomBuilder extends FormBuilder {
  RandomBuilder(el): super(el);
  InputElement get inputElement {
    var rand = new Random().nextInt(6);

    if (rand == 0) return new WeekInputElement();
    if (rand == 1) return new NumberInputElement();
    if (rand == 2) return new TelephoneInputElement();
    if (rand == 3) return new UrlInputElement();
    if (rand == 4) return new TimeInputElement();
    return new TextInputElement();
  }
}
The other piece of the pattern is the "product." The product in this case the standard InputElement from dart:html — nobody ever said that the product had be a hand-coded class, after all. Given that, the concrete products are the various types of input elements that are randomly returned from the getter factory method.

And there you have it: a simple, web implementation of the factory method pattern!

I can use this in client code by creating a new form builder element as part of a button click handler:
  var button = new ButtonElement()
    ..appendText('Build Input')
    ..onClick.listen((_){
        new RandomBuilder(container).addInput();
      });
This might be a little too simplistic, but I rather like the example. It feels accessible for most web developers. It could also serve as a building block for further examples. I may continue to explore slightly more modern examples tomorrow, though other patterns beckon. Stay tuned!


Play with the code on DartPad: https://dartpad.dartlang.org/ed63a78724e4a8605793.


Day #90

1 comment: