Method chaining using Cascade in Dart

0
20912
Method chaining using Cascade in Dart

Method chaining is a common design pattern in object-oriented programming, but do you know Google natively supports method chaining through Cascade in Dart? Let see how it works in this article.

Method Chaining

Method chaining is often being used to help developers configuring and building objects for classes having a lot of properties.

If you’re from programming languages with OOP support, this is what you do to handle method chain.

class ChainCalculator {
  double _accumulator = 0.0;

  ChainCalculator(double initVal) {
    this._accumulator = initVal;
  }

  ChainCalculator add(double val) {
    this._accumulator += val;
    return this;
  }

  ChainCalculator subtract(double val) {
    this._accumulator -= val;
    return this;
  }

  double result() {
    return this._accumulator;
  }
}

By returning this, we can receive the instance back immediately to call another method in chain.

ChainCalculator chainCalculator = ChainCalculator(0.0)
                                    .add(2.0)
                                    .subtract(1.0)
                                    .add(2.0)
                                    .subtract(2.0);
print("Result: " + chainCalculator.result().toString());

Cascade in Dart

Because Dart developers make uses of method chaining heavily, cascade feature is provided to support.

See the following code:

class Calculator {
  double _accumulator = 0;

  Calculator(double startValue) {
    this._accumulator = startValue;
  }

  void add(double val) {
    this._accumulator += val;
  }

  void subtract(double val) {
    this._accumulator -= val;
  }

  double result() {
    return this._accumulator;
  }
}

It is almost the same as ChainCalculator class; only one difference, where return this has been removed in each method.

Let’s use cascade feature.

Calculator calculator = Calculator(0.0)
    ..add(12.0)
    ..subtract(10.0)
    ..add(5.0)..subtract(8.0);

print("Result: " + calculator.result().toString());

It works perfectly and similar to previous code, but instead of . notation, cascade uses .. (double-dot) notation in order to access current modifying instance.

By using cascade, we don’t have to put many of repeated return this inside the class.

Also, another nice thing about cascade is that, since return this is unnecessary anymore, we can return something else appropriate to the methods.

Let say we want to get accumulated value immediately after calling add or subtract methods.

double add(double val) {
  this._accumulator += val;
  return this._accumulator;
}

double subtract(double val) {
  this._accumulator -= val;
  return this._accumulator;
}

The code still works, and it has no effect to cascade.

Why cascade in Dart?

Just looking at following example, it is taken from official Dart language tour.

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

Generally speaking, cascade is super-helpful for:

  • building complex objects (lots of property configuration)
  • making objects better for encapsulation. return this makes objects too open.
  • building objects faster with nested cascade.
  • less lines of code.

Well, even if you don’t like it, you will fall in love with Cascade in Dart sooner or later.

Source code for this tutorial is posted here, https://github.com/petehouston/learn-dart/blob/master/bin/cascade.dart