Monday, November 16, 2015

Lazy Initialization Wins Out


Design patterns trend mundane once you figure them out. "Oh, that's all the Flyweight is?" Given that they were originally inspired by something as fanciful as The Timeless Way of Building, I still half expect the sublime from every design pattern that I explore. The sublime may not always be there. Then again, maybe I just need to explore a little more.

I enjoy finding examples that are concise yet still show some of the power of design patterns. Certainly such examples are important for Design Patterns in Dart. But once I have them, I fear tweaking them and exploring further will yield diminishing returns—perhaps the sublime just isn't in this design pattern. On the other hand, how can I ever find the sublime if I don't explore. And so tonight I risk wasting my time in search of the sublime.

The esteemed James Hurford supplied some pointers and suggestions to my recent flyweight coffee shop. The code was excellent, as to be expected. Well, except for this bit in the flyweight:
abstract class Coffee {
  factory Coffee.create(name) => _cache.putIfAbsent(name, () => _create(name));    
  static Coffee _create(name) {
    switch(name) {
      case 'Flat White':
        return new FlatWhite();
      case 'Mockachino':
        return new Mockachino();
      case 'Cappuccino':
        return new Cappuccino();
      case 'Espresso':
        return new Espresso();
      case 'Frappe':
        return new Frappe();
      case 'Long Black':
        return new LongBlack();
      case 'Americano':
        return new Americano();
    }
    
    return new FakeCoffee();
  }
}
I'm not giving James too hard a time here. The code has two things that I appreciate: it works and it produces concrete flyweight instances of different varieties. I always like working code and I appreciate concrete instances because Dart's static typing is one of the things I very much want to explore in the book.

But that case statement: ick. Not only is it long and unsightly, but it also necessitates two changes every time a new coffee drink is added to the menu. Maybe the load-time fun from last night can help. Or not...

Following along with the DWT approach, I ought to be able to define a concrete flyweight along the lines of:
class Mochachino implements Coffee {
  static var type = Coffee.register(new Mochachino());
  String get name => "Mochachino";
  double get profitPerOunce => 0.3;
}
Registering the Mochachino will cache a reference to the flyweight instance such that all future instances will be the original. Except this does not work.

I did not give this enough thought last night, but the DWT must be so old that some of the code, the flyweight implementation included, no longer works because of lazy initialization. Lazy initialization is great until you expect code like the type assignment to be evaluated at compile time.

For type to be registered at compile-time, I need to use the const keyword instead of new. Unfortunately, adding objects to a Map at compile-time does not lend itself to compile-time constants.

In other words, I think I'm out of luck. If I want concrete flyweight objects, I either need to stick with James' long case statement approach or move away from factory constructor back to factory classes. Neither is particular appealing, but I might opt for the latter as that was how the original pattern was envisioned. That is something to explore tomorrow.



Day #5

No comments:

Post a Comment