💊

Dartのabstractとは?

2022/04/30に公開

Dartにもインターフェイスがあった!

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

英語の「Interface」は「境界面」「接点」などの意味があり、「インターフェース」は、2つのものを仲介するという意味を持っています。人と人の間に使用することはなく、システム間や人間と機械の間によく使う言葉です。

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

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

abstract class 抽象クラス名 {
}

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

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

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

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

これだけだと、何のことかイメージが湧かないですね🤔
戦車を題材として、プログラムを作ってみました。
フォルダ構成

.
└── military_vehicle
    ├── derivation
    │   ├── countryA_tank.dart
    │   ├── countryB_tank.dart
    │   └── country_if.dart
    ├── main.dart
    └── original
        ├── tank.dart
        ├── tankA.dart
        └── tankB.dart

まずは、輸出する国が作った戦車の情報が書かれたプログラムを作成
こちらが、抽象的なクラスというものですね。

抽象的とは、共通した要素を抜き出して一般化していること、または具体性に欠けていて実態が明確ではないことである。

国語の問題みたい😅
つまり、「まだ決まってないよ...」ってことか?

tank.dart

// 輸出した国のオリジナルの戦車のインターフェースクラス
abstract class OriginTank {

  // 装備を表す抽象メソッドを用意
  // 各OSクラスで実態を記述する
  void quipment();
}

tankA.dart

import 'tank.dart';

class TankA implements OriginTank {
  final String _type;
  TankA(this._type);

  
  void quipment() {
    print('こちらの製品は、$_type高性能な装備です。');
  }
}

tankB.dart

import 'tank.dart';

class TankB implements OriginTank {
  final String _type;
  TankB(this._type);

  
  void quipment() {
    print('こちらの製品は、$_type装備が貧弱で、旧式の兵器です。');
  }
}

輸出先の戦車のインターフェースを作りましょう

country_if.dart

// 輸出先の戦車のインターフェース
abstract class CountryIf {
  void information();
}

countryA_tank.dart

// 戦車の装備を継承して
// 輸出先の国独自の実態を作成
import '../original/tankA.dart';
import 'country_if.dart';

class CountryA extends TankA implements CountryIf {
  CountryA(String type) : super(type);

  
  void information() {
    print('これは、A国に輸出された戦車です');
    super.quipment();
  }
}

countryB_tank.dart

// 戦車の装備を継承して
// 輸出先の国独自の実態を作成
import '../original/tankB.dart';
import 'country_if.dart';

class CountryB extends TankB implements CountryIf {
  CountryB(String type) : super(type);

  
  void information() {
    print('これは、B国に輸出された戦車です');
    super.quipment();
  }
}

これで、プログラムを作り終わりましたね🔨
では、こちらのファイルから実行しましょかね。

main.dart

import 'derivation/countryA_tank.dart';
import 'derivation/countryB_tank.dart';
import 'derivation/country_if.dart';

void main() {
  CountryIf countryA = CountryA('120mm滑空砲を搭載した戦車です。');
  CountryIf countryB = CountryB('装甲が貧弱な戦車です。');
  countryA.information();
  countryB.information();
}

私は、VScodeを使っているので、Runボタンを押して実行しています。
右上の虫のボタンでもプログラムの実行はできます。

実行結果

Connecting to VM Service at http://127.0.0.1:50713/q_bqUA93eq4=/
これは、A国に輸出された戦車です
こちらの製品は、120mm滑空砲を搭載した戦車です。高性能な装備です。
これは、B国に輸出された戦車です
こちらの製品は、装甲が貧弱な戦車です。装備が貧弱で、旧式の兵器です。
Exited

やってみた感想

abstract、implements知らない文法がまだまだDartにはありました😵‍💫
これを理解できればFlutterの学習も以前より、理解しやすくなるのでは?と思いました。
今学習している内容がオブジェクト思考を理解できていないと、分からないことに躓いてますね。

オブジェクト指向
オブジェクト指向とは、コンピュータプログラムの設計や実装についての考え方の一つで、互いに密接に関連するデータと手続き(処理手順)をオブジェクト(object)と呼ばれる一つのまとまりとして定義し、様々なオブジェクトを組み合わせて関連性や相互作用を記述していくことによりシステム全体を構築していく手法。

子供むけの教育事業で内容がFlutterのWidgetが何をしているのか、理解しやすくしてくれるブログを見つけました。
「クラス(プログラム全体の設計図)を分割し」、この表現が参考になりました💡
https://robo-done.com/blog/2021/04/doneship_object_oriented/

おまけ

デザインパターンなるものも勉強したので、書いてみました。こちらは、テンプレートメソッドパターンと呼ばれているものです。
やっていることは、単純で抽象クラスとメソッドを用意して、作った処理を全て実行するメソッドで、コンソールに処理を表示するだけです。
すみません。すごいの作りたかったのですが、まだそこまでできなくて🙇‍♂️

抽象クラスとメソッドを作成

template_pattern.dart

// 抽象クラスを作成
// 継承したクラスに実装してほしいもの。テンプレートとなるメソッドを作成

abstract class TemplatePattern {
  // 朝やっていること
  void morningRoutine();
  // お昼にやっていること
  void afternoonRoutine();
  // 夜にやっていること
  void nightRoutine();

  // 1日の流れを実行するメソッド
  void runToday() {
    print('朝のルーティン');
    morningRoutine();
    print('------------');
    print('昼のルーティン');
    afternoonRoutine();
    print('------------');
    print('夜のルーティン');
    nightRoutine();
    print('------------');
  }
}

抽象クラスを継承して、メソッドをオーバーライドする

import 'template_pattern.dart';

class remoteEngineer extends TemplatePattern {

  List todoMorning = <String>[
  "- コーヒーを飲みならがお仕事",
  "- 洗濯をする",
  "- ちょっと散歩してくる"
  ];

  List todoAfterNoon = <String>[
    "- Ubarイーツでイタリアンを注文",
    "- お昼ごはん食べながらお仕事",
    "- おしゃべりクッキングを見る"
  ];
  List todoNight = <String>[
    "- お風呂に入る",
    "- 夜ご飯を食べる",
    "- Netflixを見る"
  ];

  
  void morningRoutine() {
    todoMorning.forEach((e) => print(e));
  }

  
  void afternoonRoutine() {
    todoAfterNoon.forEach((e) => print(e));
  }

  
  void nightRoutine() {
    todoNight.forEach((e) => print(e));
  }
}

main.dartでクラスをインスタンス化して実行する

import 'template_method/engineer.dart';

void main() {
  remoteEngineer remoteWork = remoteEngineer();

  remoteWork.runToday();
}

実行結果

朝のルーティン
- コーヒーを飲みならがお仕事
- 洗濯をする
- ちょっと散歩してくる
------------
昼のルーティン
- Ubarイーツでイタリアンを注文
- お昼ごはん食べながらお仕事
- おしゃべりクッキングを見る
------------
夜のルーティン
- お風呂に入る
- 夜ご飯を食べる
- Netflixを見る
------------
Exited

Discussion