Dart で JavaのEnumっぽいことをする

DartのenumはJavaのenumと比べて、非力かと思っています。

  • Dart
  • 値を羅列するだけ。

enum JobType {
	proper,
	parttime,
}
  • Java
  • enumの一つの値に対して、データを持つことができる。

    enum JobType {
    	PROPER(100),
    	PARTTIME(200),
    
    	private final int salary;
    	private ResultCode(int salary) {
    		this.salary = salary;
    	}
    	int getSalary() {
    		return salary;
    	}
    }
    

    Dartでenumの値に、名前やメソッドを付随させようとすると、swich文で実現させます。
    そこで、DartでもJavaのように、値や関数を定義できるようにしたenumっぽいことをしようと思います。

    想定

    ユーザ登録時にDropdownMenuで「正社員」「パート」のJobTypeを選択させる。JobTypeで給与の計算方法を変更する。

    JobTypeの定義

    typedef GetSalary = int Function(int rage, int totalTime, int workTime);
    class JobType {
      JobType._(this.name, this._getSalary);
    
      final String name;
      final GetSalary _getSalary;
    
      int getSalary(int salary, int total, int workTime) {
        return _getSalary(salary, total, workTime);
      }
    
      static final proper =
          JobType._('正社員', (salary, total, workTime) => salary * workTime ~/ total);
      static final parttime =
          JobType._('パート', (rage, total, workTime) => workTime * rage);
    
      static final List values = List.unmodifiable([
        proper,
        parttime,
      ]);
    }
    
    
    • プライベートコンストラクタにすることで、外部でインスタンスを生成できなくする
    • enumの値にあたるものをstatic final で定義することで、JobType.properという形でアクセスでるようにする
    • 引数の型をJobTypeにした場合、JobType.properとJobType.pattimeしか選択できなくする(enum的)
    • 給与を求めるファンクションの型を決めている。基本給与、総合時間、業務時間を渡すと、給与が計算される。
    • 正社員には、基本給与*(業務時間/総合時間)の給与が支払われる
    • パートには、時給*業務時間 の給与が支払われる
    • DropdownMenuには、正社員、パートとして選択肢が表示される
    • 一覧を取得できるようにvaluesのListを作る。他から変更できないように、List.unmodifiableを付ける

    ユーザの定義

    給与とJobTypeを設定する。あと、給与計算の方法を定義しているが、その中にJobTypeの給与計算を呼ぶようにしてある。そのため、JobTypeで定義した計算ができる。

    class User {
      User(this.salary, this.jobType);
    
      final JobType jobType;
      final int salary;
    
      int getSalary(int total, int workTime) {
        return jobType.getSalary(salary, total, workTime);
      }
    }
    

    実際の使用

    ちゃんとenumみたいに定義が一つのインスタンスであるか、のテスト。JobTypeを変更して、別々の計算方法でちゃんと正しく計算されているか、確認してます。

    main() {
      test('基本', () async {
        expect(JobType.proper == JobType.proper, isTrue);
        expect(JobType.proper == JobType.parttime, isFalse);
        expect(JobType.parttime == JobType.parttime, isTrue);
    
        expect(JobType.proper.name, '正社員');
        expect(JobType.proper.getSalary(500000, 100, 100), 500000);
        expect(JobType.parttime.getSalary(1000, 100, 10), 10000);
    
        User user = User(100000, JobType.proper);
        expect(user.getSalary(1000, 500), 50000);
    
        User part = User(1000, JobType.parttime);
        expect(part.getSalary(1000, 30), 30000);
      });
    }
    

    まとめ

    ということで、JavaのEnumをDartで実現してみました。Javaも昔はこんな方法を使っていたと思います。そのうち、Dartでも言語ベースで実装されるとよいのですが。
    DropdownMenuの選択肢として使用するのが、とりあえず一番相性がいいかと思っています。参考になりどこかで使って頂けると嬉しいです!