【Dart】簡単なユーザクラスを利用してNamed,Redirecting,Factoryコンストラクタ理解

公開:2020/12/07
更新:2020/12/08
10 min読了の目安(約9600字TECH技術記事

【Dart】コンストラクタ関連

  • 【参考】公式のConstructors学習サイト

  • 利用するサンプルクラス

    • SNSアプリが持つようなUserクラス
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });
}

Named constructors

  • Named constructorsは、特定の目的のために特定の値を格納するためのコンストラクタ

基本例①

  • anonymous(匿名)ユーザを作成する用のコンストラクタ
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Named constructors
  User.anonymous()
      : id = 'anonymousId',
        username = 'anonymousUsername',
        email = 'anonymousEmail';
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail

基本例②

  • 引数をとる場合
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Named constructors
  User.anonymous({String username})
      : id = 'anonymousId',
        username = username,
        email = 'anonymousEmail';
}

void main() {
  User user = User.anonymous(username: 'TestUser');
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
TestUser
anonymousEmail

Redirecting constructors

  • Redirecting constructorsは、他のコンストラクタを流用するためのコンストラクタ

基本例①

  • 通常のコンストラクタを利用し、anonymous(匿名)ユーザを作成する用のコンストラクタ
    • ※書き方が違うのみで、Named constructorとほぼ同様
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Redirecting constructors
  User.anonymous()
      : this(
          id: 'anonymousId',
          username: 'anonymousUsername',
          email: 'anonymousEmail',
        );
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail

基本例②

  • 引数をとる場合
    • ※これも書き方が違うのみで、Named constructorとほぼ同様
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Redirecting constructors
  User.anonymous({String username})
      : this(
          id: 'anonymousId',
          username: username,
          email: 'anonymousEmail',
        );
}

void main() {
  User user = User.anonymous(username: 'TestUser');
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
TestUser
anonymousEmail

基本例③

  • コンストラクタに初期値がある場合に、コード量を節約可能
    • ※Named constructorsでは、エラーとなる(メインコンストラクタに初期値があった場合も、記載が必要)
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username = 'TestUser',
    this.email,
  });

  // Redirecting constructors
  User.anonymous()
      : this(
          id: 'anonymousId',
          email: 'anonymousEmail',
        );
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
TestUser
anonymousEmail

基本例④

  • Named constructorも簡単に流用可能
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Named constructors
  User.anonymous({String username})
      : id = 'anonymousId',
        username = username,
        email = 'anonymousEmail';

  // Redirecting constructors
  User.anonymousTestUser() : this.anonymous(username: 'TestUser');
}

void main() {
  User user = User.anonymousTestUser();
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
TestUser
anonymousEmail

Factory constructors

  • Factory constructorsは、インスタンスを必要な際に作成するコンストラクタ(returnでインスタンスを返す)
    • ※Factoryと通常コンストラクタは同じ名前のコンストラクタ不可

基本例①

  • anonymous(匿名)ユーザをその場で作成し、return
    • ※書き方が違うのみで、Named constructor、Redirecting constructorsとほぼ同様
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Factory constructors
  factory User.anonymous() {
    return User(
      id: 'anonymousId',
      username: 'anonymousUsername',
      email: 'anonymousEmail',
    );
  }
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail

基本例②

  • 引数をとる場合
    • ※これも書き方が違うのみで、Named constructor、Redirecting constructorsとほぼ同様
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Factory constructors
  factory User.anonymous({String username}) {
    return User(
      id: 'anonymousId',
      username: username,
      email: 'anonymousEmail',
    );
  }
}

void main() {
  User user = User.anonymous(username: 'TestUser');
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
TestUser
anonymousEmail

基本例③

  • ユーザ情報が入ったドキュメント(ここではdocというMap)を引数とし、anonymous(匿名)ユーザを作成することを想定
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Factory constructors
  factory User.fromDocument(Map doc) {
    return User(
      id: doc['id'],
      username: doc['username'],
      email: doc['email'],
    );
  }
}

void main() {
  User user = User();
  final doc = {'id': 'anonymousId', 'username': 'anonymousUsername', 'email': 'anonymousEmail'};
  user = User.fromDocument(doc);
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail

基本例④

  • ユーザ情報が入ったドキュメント(ここではdocというMap)を引数とし、ユーザを作成することを想定
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Factory constructors
  factory User.fromDocument(Map doc) {
    return User(
      id: doc['id'],
      username: doc['username'],
      email: doc['email'],
    );
  }
}

void main() {
  User user = User();
  final doc = {'id': '001', 'username': 'TestUser', 'email': 'test@email.com'};
  user = User.fromDocument(doc);
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

001
TestUser
test@email.com

基本例⑤

  • 一度anonymous(匿名ユーザ)等でインスタンス作成後に、中身を入れなおすことが可能
class User {
  final String id;
  final String username;
  final String email;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Named constructors
  User.anonymous()
      : id = 'anonymousId',
        username = 'anonymousUsername',
        email = 'anonymousEmail';

  // Factory constructors
  factory User.fromDocument(Map doc) {
    return User(
      id: doc['id'],
      username: doc['username'],
      email: doc['email'],
    );
  }
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
  final doc = {'id': '001', 'username': 'TestUser', 'email': 'test@email.com'};
  user = User.fromDocument(doc);
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail
001
TestUser
test@email.com

基本例⑥

  • User.fromDocumentを利用したユーザ作成を一度のみに制限
    • ※returnでインスタンスを返すでインスタンスを返す書き方のため、必ずしもインスタンスを作成しない
class User {
  final String id;
  final String username;
  final String email;
  static bool _isCreated = false;

  User({
    this.id,
    this.username,
    this.email,
  });

  // Named constructors
  User.anonymous()
      : id = 'anonymousId',
        username = 'anonymousUsername',
        email = 'anonymousEmail';

  // Factory constructors
  factory User.fromDocument(Map doc) {
    if (_isCreated) {
      print('正規ユーザを作成済みです。');
    } else {
      _isCreated = true;
      return User(
        id: doc['id'],
        username: doc['username'],
        email: doc['email'],
      );
    }
  }
}

void main() {
  User user = User.anonymous();
  print(user.id + '\n' + user.username + '\n' + user.email);
  final doc = {'id': '001', 'username': 'TestUser', 'email': 'test@email.com'};
  user = User.fromDocument(doc);
  print(user.id + '\n' + user.username + '\n' + user.email);
  user = User.fromDocument(doc);
}

実行結果

anonymousId
anonymousUsername
anonymousEmail
001
TestUser
test@email.com
正規ユーザを作成済みです。

基本例⑦(備考)

  • Private constructorとFactory constructorを利用
    • User user = User(doc);と呼んだ際に、以下のFactory constructor→Private constructorと実行される
class User {
  final String id;
  final String username;
  final String email;

  // Private constructor
  User._({
    this.id,
    this.username,
    this.email,
  }) {
    print('TEST:A');
  }

  // Factory constructors
  factory User(Map doc) {
    print('TEST:B');
    return User._(
      id: doc['id'],
      username: doc['username'],
      email: doc['email'],
    );
  }
}

void main() {
  final doc = {'id': '001', 'username': 'TestUser', 'email': 'test@email.com'};
  User user = User(doc);
  print(user.id + '\n' + user.username + '\n' + user.email);
}

実行結果

TEST:B
TEST:A
001
TestUser
test@email.com