スタッフブログ

STAFF BLOG

アプリ開発日誌

2021.09.30

Flutter開発のためのDart入門(7)クラス②

Dart_programming_language_logo

前回の投稿に続き、今回もDartについて解説していきます。
引き続きクラスについて解説します。

抽象クラス

抽象クラスとは継承されることを前提として、処理内容を記述しないメソッド(抽象メソッド)を含むクラスです。
抽象クラス単体ではインスタンス化することはできません。

反対にインスタンス化できるクラスは具象クラスと呼びます。
抽象クラスを定義する際はabstractキーワードを指定します。

abstract class 抽象クラス名 {
}

抽象メソッド

抽象クラスには抽象メソッドを定義できます。

抽象メソッドには処理内容を記述できません。

メソッド名()の後ろの{処理内容}の代わりにセミコロン;を記述します。

abstract class Shape {
  double getArea(); // 抽象メソッド
}

継承

既存のクラスを元に新たなクラスを定義することを継承と呼びます。
また、継承において、元となるクラスをスーパークラス、新たに定義されるクラスをサブクラスと呼びます。
サブクラスを定義する際には、extendsキーワードを使用します。

次のコードは先程の抽象クラスを継承した例です。

abstract class Shape { // 抽象クラス
  double getArea(); // 抽象メソッド
}

// 抽象クラスを継承
class Rectangle extends Shape {
  double width = 0;
  double height = 0;

  Rectangle(this.width, this.height);

  // 抽象メソッドを実装
  double getArea() {
    return this.width * this.height;
  }
}

void main() {
  var rect = Rectangle(3, 4);
  print('四角形の面積は${rect.getArea()}㎠');
}

実行結果

四角形の面積は12㎠

※Dartでは総てがオブジェクトです。Javaのプリミティブ型(intやbooleanなどのデータ型)のようなものは存在しません。すべてのオブジェクトは Objectクラスを継承しています。

オーバーライド

オーバーライドとは、スーパークラスで定義しているメソッドを、同じ名前でサブクラスで再定義することです。
スーパークラスで定義したメソッドと目的は同じであるが、処理が異なるメソッドを定義する場合に使用します。
@overrideアノテーションを使用して、意図的にメソッドをオーバーライドしていることを示すことができます。

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}

暗黙的インターフェイス

インターフェースとは

インターフェースとは簡単に言うと、公開されたクラスの取り決めのことです。
ほとんどのインターフェイスは処理内容を含まない抽象クラスから作成されます。
DartにはJavaのように明示的にインターフェイスを宣言するinterfaceキーワードはありません。

インターフェースを実装する場合、extendsではなくimplementsキーワードを使用します。

// 抽象クラスA
abstract class クラスA {
  void someMethod();
}

// クラスAインターフェースの実装
class クラスB implements クラスA {
    void someMethod() {
        処理内容
    }
}

※JavaやKotlinのinterface、Swiftのprotocolにあたります。

暗黙的インターフェース

前述の通り、Dartには明示的なインターフェースはありません。
代わりに、任意のクラスをインターフェースとして使用できます。
これはすべてのクラスにあらかじめ暗黙的にインターフェースが定義されているためです。

次のコードではImpostorクラスはPersonクラスを実装(implements)しています。

ImpostorクラスはPersonクラスのインターフェースをすべて実装する必要があります。

// 暗黙的インターフェイスPersonにはgreet()メソッドが含まれています
class Person {
  final String _name;

  Person(this._name);

  String greet(String who) => 'Hello, $who. I am $_name.';
}

// Personインターフェースの実装
class Impostor implements Person {
  String get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

実行結果

Hello, Bob. I am Kathy.
Hi Bob. Do you know who I am?

列挙型

列挙型とはいくつかの定数をひとまとまりにして扱えるようにしたもので、プログラマが任意に定義できます。

enumキーワードを使用して列挙型を宣言します。

次のコードはswich文で列挙型を使ったコードです。

※列挙型のすべての値を条件に含めないと警告が出ます。

enum Color { red, green, blue }

void main() {
  var aColor = Color.blue;

  switch (aColor) {
    case Color.red:
      print('Red as roses!');
      break;
    case Color.green:
      print('Green as grass!');
      break;
    default:
      print(aColor);
  }
}

実行結果

Color.blue

クラス変数

クラス変数やクラスメソッドは、クラス全体で扱うデータを格納するために使用します

クラス変数、クラスメソッドはそれぞれstatic変数、staticメソッドとも呼ばれます。
呼び出す際には、クラス名.static変数名クラス名.staticメソッド名()で呼び出します。
実装する際はstaticキーワードを指定します。

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

クラスメソッド

クラスメソッドはインスタンス上では動作しないので、thisにアクセスすることはできません。

しかし、クラス変数にはアクセスできます。次の例では、クラス上で直接スタティックメソッドを呼び出しています。

import 'dart:math';

class Point {
  double x, y;
  Point(this.x, this.y);

  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

実行結果

2.8284271247461903

ジェネリクス(総称型)

以前、List型の解説でList<String>のように<>内に型を指定していました。
ジェネリクス型でクラス定義をおこなうことにより、クラス内で型を事前に決めるのではなく、クラス利用時に決定できます
次のコードはmain()関数内で指定したString型の値とint型の値を同じクラス定義であつかっています。

class GenericMember<T> {
  final List<T> _memberList = [];
  void push(T item) => _memberList.add(item);
  T pop() => _memberList.removeLast();
  get memberList => _memberList;
}

void main() {
  final memberA = GenericMember<String>();
  memberA.push("Ken");
  memberA.push("Bob");
  //memberA.push(1);
  print(memberA.memberList);

  final memberB = GenericMember<int>();
  memberB.push(1);
  memberB.push(2);
  memberB.push(3);
  print(memberB.memberList);
  memberB.pop();
  print(memberB.memberList);
}

実行結果

[Ken, Bob]
[1, 2, 3]
[1, 2]

クラス名に続く<>はダイヤモンド演算子と呼ばれており、Tのことを型パラメータといいます。

<T>の他に<E>や<K, V>などがあり、これらは汎用的な型、つまり、仮の型を使用することを表すために使用します。

型パラメータの名前は任意でかまいませんが、通常は意味のある大文字1文字が使用されます。
※TはType、EはElement、KはKey、VはValueの頭文字を意味しています

ジェネリクス型を使用することによりシンプルで安全なコードが実現できます。

ライタープロフィール

【N】
Webエンジニアの経験を経て、アプリエンジニアとしてEDAに入社。
Flutter開発導入のファシリテーターとして、勉強会などを担当している。

BACK

お問合せ

イーディーエーに興味をお持ちいただいて
ありがとうございます!
スマホアプリに関するご相談、
お見積りや弊社へのご質問など、
お気軽にお問い合わせください。
担当者より折り返しご連絡させていただきます。

    お名前必須
    会社名
    メールアドレス必須
    電話番号必須
    お問合わせ種別必須
    お問合わせ内容必須

    アンケートにご協力ください。
    弊社サイトへはどのようにしてアクセスされましたか?

    個人情報のお取扱いに関する同意事項

    1.事業者の氏名又は名称

    株式会社イーディーエー

    2.個人情報保護管理者の氏名又は職名、所属及び連絡先

    個人情報保護管理者 小宮 保人
    Mail:[email protected]

    3.取得した個人情報の利用目的

    当フォームで取得した個人情報は、お問い合わせに関する回答のために利用し、目的外利用はいたしません。

    4.弊社が取得した個人情報の第三者への委託、提供について

    弊社は、ご本人に関する情報をご本人の同意なしに第三者に委託または提供することはありません。

    5.個人情報保護のための安全管理

    弊社は、ご本人の個人情報を保護するための規程類を定め、従業者全員に周知・徹底と啓発・教育を図るとともに、その遵守状況の監査を定期的に実施いたします。
    また、ご本人の個人情報を保護するために必要な安全管理措置の維持・向上に努めてまいります。

    6.個人情報の開示・訂正・利用停止等の手続

    ご本人が、弊社が保有するご自身の個人情報の、利用目的の通知、開示、内容の訂正、追加又は削除、利用の停止、消去及び第三者への提供の停止を求める場合には、下記に連絡を頂くことで、対応致します。

    株式会社イーディーエー 個人情報お問合せ窓口
    〒106-0032 東京都港区六本木7丁目14番23 ラウンドクロス六本木4F
    TEL:03-5422-7524 FAX:03-5422-7534
    Mail:[email protected]

    7.ご提供いただく情報の任意性

    個人情報のご提供は任意ですが、同意を頂けない場合には、第3項にあります利用目的が達成できない事をご了承いただくこととなります。

    8.弊社Webサイトの運営について

    弊社サイトでは、ご本人が弊社Webサイトを再度訪問されたときなどに、より便利に閲覧して頂けるよう「クッキー(Cookie)」という技術を使用することがあります。これは、ご本人のコンピュータが弊社Webサイトのどのページに訪れたかを記録しますが、ご本人が弊社Webサイトにおいてご自身の個人情報を入力されない限りご本人ご自身を特定、識別することはできません。
    クッキーの使用を希望されない場合は、ご本人のブラウザの設定を変更することにより、クッキーの使用を拒否することができます。その場合、一部または全部のサービスがご利用できなくなることがあります。