エキサイト株式会社の武藤です。
Flutterを使ったアプリ開発のプロジェクトにジョインしました。 Dartを触ってみて、コンストラクタにいくつか種類があることがわかったので、整理してみたいと思います。
コンストラクタ
通常のコンストラクタです。コンストラクタ引数をプロパティーにセットします。
class Book { String title = ''; Book(String title) { this.title = title; } } void main() { var book = Book('my book'); print(book.title); // my book }
上記を省略して、下記のように記述できます。
class Book { String title; Book(this.title); }
この記法の場合では、プロパティーの初期値を設定しないで済みます。
デフォルトコンストラクタ
コンストラクタを記述しない場合、デフォルトとして引数を持たないコンストラクタがコンパイル時に定義されます。
class Book { String title = "my book"; } void main() { var book = Book(); print(book.title); // my book }
Dartでは、サブクラスはスーパークラスのコンストラクタを継承しません。そのため、サブクラスでコンストラクタを定義しない場合にデフォルトのコンストラクタが定義されます。
名前付きコンストラクタ
コンストラクタに名前をつけて、用途に応じて呼び出すことができます。
class Blog { String title; Blog(this.title); Blog.draft() : title = 'draft title'; } void main() { var book = Blog.draft(); print(book.title); // draft title }
リダイレクトコンストラクタ
コンストラクタから別のコンストラクタを呼び出すことができます。 名前付きコンストラクタと似ており、用途に応じて別名を付けられます。
class Todo { Todo(this.name, this.elapsedTime); Todo.newTask(): this('new task', Duration()); String name; // 経過時間 Duration elapsedTime; } void main() { var todo =Todo.newTask(); print(todo.name); // new task print(todo.elapsedTime); // 0:00:00.000000 }
定数コンストラクタ
オブジェクトを定数として扱う際に使われます。コンストラクタに const をつけます。
class HttpStatus { const HttpStatus(); final int OK = 200; final int BAD_REQUEST = 400; } void main() { var httpStatus = HttpStatus(); print(httpStatus.OK); }
オブジェクト定数を扱う場合はパフォーマンスを考慮して、複数回のインスタンス生成を避けたいことがあります。
下記のように、private constructorにより一度だけインスタンス生成をします。 インスンタンス生成が外部からされなくなり、インスンタンスを1つに保つことができます。
class HttpStatus { const HttpStatus._(); static final int OK = 200; static final int BAD_REQUEST = 400; } void main() { // コンストラクタにアクセスできないのでエラーになる // var httpStatus = new HttpStatus(); print(HttpStatus.OK); }
ファクトリコンストラクタ
ファクトリコンストラクタでは、コンストラクタのロジックを独自に記載できます。 それは、例えば、常に新しいインスタンス生成せず、既に生成されたインスタンスを返すシングルトンパターンの実装に使えます。
class Book { String title; static var _instance; factory Book(String title){ _instance ??= Book._internal(title); return _instance; } Book._internal(this.title); } void main() { var book1 = Book('my book1'); var book2 = Book('my book2'); print(book1.title); // my book1 print(book2.title); // my book1 print(book1 == book2); // true }
book2はbook1と同一のインスタンスとなります。
ファクトリコンストラクタは、単純な生成処理以外にロジックをもたせることもできます。 その一例として、Flutterで使われるFreezedパッケージのJSONのパース処理等を見かけます。 下記のコードは、公式ページから引用したものです。
@freezed class Person with _$Person { const factory Person({ required String firstName, required String lastName, required int age, }) = _Person; factory Person.fromJson(Map<String, Object?> json) => _$PersonFromJson(json); }
終わりに
Dartを書くにあたり、複数のコンストラクタが出てきたので、その種類について整理しました。 これまでにPHP、Java、Kotlin等を触ってきましたが、初めて触る機能があり、とてもおもしろかったです。
参考になれば幸いです。