こんばんは。最近Flutterでアプリ開発をしているとりかつです。
Dartにはコンストラクタが数種類あるのですが、Flutterをはじめたてのころ、けっこうつまづきました。
そこで今回の記事ではDartのコンストラクタの種類と使い方について紹介したいと思います。
Generative Constructor
ここでは生成的コンストラクタ(通常のコンストラクタ)を紹介していきます。
通常のコンストラクタ
Dartのコンストラクタはクラス名で宣言します。Javaを触ったことのある人には馴染みがあるかと思います。
class Sample { Sample(String text) { someField = text; } String someField; }
フィールド代入の省略
これで動作はするのですが、もうひと工夫加えたいと思います。
Dartにはコンストラクタでのフィールド代入を省略する機能があります。
以下のようにコンストラクタの引数でthis.hogehoge
としてやるだけです。さらに、コンストラクタの処理がない時は{・・・}
を省略することができます。
class Sample { Sample(this.someField); String someField; }
簡単ですね。 こうするとコードの行数が減るだけでなく、変数名を考える手間も省けるので生産性が上がりそうです。
積極的につかっていきましょう。
ネームドコンストラクタ
Dartではコンストラクタのオーバーロードがサポートされていません。 その代わり、ネームドコンストラクタがあります。
以下は色を表すクラスです。
class Color { Color.fromRGB(this.r, this.g, this.b) { alpha = 1.0; } Color.fromRGBA(this.r, this.g, this.b, this.a); /// red int r; /// green int g; /// blue int b; /// alpha double alpha; }
このようにクラス名.コンストラクタ名
で宣言できます。
これも簡単ですね。
ネームドコンストラクタをつかうことで、どうやってインスタンスを生成しているかが明確になります。
ネームドコンストラクタの命名にはfrom
キーワードを使うとインスタンス生成時のコードが自然言語ライクになるので個人的にオススメです。
/// fromを使わない場合 final color = Color.RGB(100, 20, 49); /// fromを使った場合 final color = Color.fromRGB(100, 20, 49);
オプショナルパラメータを使えばもっとスマートに実装できますが、それについてはここでは触れないどきます。
定数コンストラクタ
Dartには定数コンストラクタというものがあります。 以下は定数コンストラクタの例です。
class Sample{ const Sample(this.text); final String text; }
コンストラクタの先頭にconst
がついているのがわかると思います。
これが定数コンストラクタです。
定数コンストラクタを使うことで、インスタンスの生成時にconst
キーワードをつけて、定数オブジェクトをインスタンス化することができます。
const Sample('サンプル');
定数コンストラクタを宣言する条件は以下の2つです。
- クラスのフィールドが全て
final
- コンストラクタのボディがない(InitializerListはOK)
少し難しく感じますが、慣れてくるとなんてことはなくなります。
ユースケースとしてはパフォーマンスの向上が考えられます。
FlutterのStreamなんかがわかりやすいと思います。
以下のコードはStereamBuilder
の例です。
StreamBuilder<String>( stream: textStream, builder: (context, snapshot) => Column( children: <Widget>[ /// text widget A Text(snapshot.data), /// text widget B Text('サンプル'), ], ), );
この場合、steramに値が流れてくるたびにtext widget A
とtext widget B
が更新されます。
text widget B
のコンストラクタの引数は'サンプル'
という定数の文字列のため、const
キーワードをつけて定数化することができます。
StreamBuilder<String>( stream: textStream, builder: (context, snapshot) => Column( children: <Widget>[ /// text widget A Text(snapshot.data), /// text widget B const Text('サンプル'), ], ), );
text widget B
は定数のため、streamに値が流れてきても再描画されるのはtext widget A
のみで済みます。
今回の例では、パフォーマンスへの影響はほとんどありませんが、「チリも積もれば山となる」ので、積極的に使っていきましょう。
終わりに
本当はファクトリコンストラクタまで紹介しようと思ったのですが、寝るのが遅くなってしまいそうなので、次回の記事で紹介したいと思います。
Dartでコンストラクタをつかいこなすことは可読性とパフォーマンスの向上に大きく貢献すると思うので、ぜひみなさんもコンストラクタとお友達になりましょう。