【Flutter/Dart】Class(クラス)の定義と使い方!アクセス制御の方法

この記事からわかること
- Flutter/DartのClass(クラス)とは?
- アクセスをプライベートに限定する方法
- ゲッター・セッターや継承などの使い方
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Koala
- Xcode:16.0
- Flutter:3.29.2
- Dart:3.7.2
- Mac M1:Sonoma 14.6.1
オブジェクト指向型のプログラミング言語に欠かせないクラス。Dartもオブジェクト指向型のプログラミング言語であり、クラスが使用可能です。
今回はDartのクラスの使い方と出来ること、メリットなどを自分なりにまとめていきたいと思います。
オブジェクト指向型プログラミングとは?
「オブジェクト指向プログラミング」とはプログラミングの手法(プログラミングパラダイム)の種類の1つです。他にも関数型プログラミングや命令型プログラミング、手続型プログラミングなどがあります。
オブジェクト指向型プログラミングの特徴はオブジェクトと呼ばれるデータ構造を定義してプログラムを記述していくことです。このオブジェクトには固有のデータ(プロパティ)と固有の処理(メソッド)を用意しておき、外部からの呼び出しに応じてデータを操作していきます。
オブジェクトはプロパティやメソッドを持ったデータ構造の雛形や設計図のようなものであり、使用するにはその設計図を元に作成された実体を使用します。これをインスタンスと呼び作成することをインスタンス化と呼びます。
メリット
オブジェクト指向型プログラミングの大きなメリットは扱うデータのスコープ(使用範囲)や使い方を制御しやすいという点です。オブジェクト内でデータとそれを操作するメソッドを完結することで外部からは複雑な操作を意識する必要がなく利用することができます。これをカプセル化と呼びます。
まとめ
- オブジェクト指向型プログラミングはプログラミングパラダイムの1つ
- オブジェクトはデータ構造の設計図
- 使用する際はインスタンス化して使う
- インスタンス化とは設計図を元に実体を作ること
- メリットはデータ情報を隠蔽でき、制御できること
Dartのクラスとは?
Dartではクラスをclass
を使って宣言します。中には扱うデータであるプロパティ(変数)とメソッド(関数)を定義していきます。
class Person {
// プロパティ(変数)
String name;
int age;
// コンストラクタ(初期化)
// thisを使って自身を参照
Person(this.name, this.age);
// メソッド(関数)
void introduce() {
print("こんにちは、私は$name です。年齢は $age 歳です。");
}
}
インスタンス化
インスタンス化するためには定義したコンストラクタを使用して必要な引数を渡します。インスタンスからはドットシンタックスでメソッドやプロパティを参照することができます。
// クラスのインスタンスを作成
Person person = Person("太郎", 25);
person.introduce(); // こんにちは、私は太郎 です。年齢は 25 歳です。
print(person.age); // 25
プライベートアクセス
DartはSwiftやKotlinのようにpublic
やprivate
といったアクセス修飾子が存在しません。ではどのようにアクセスを制御するのかというと先頭に_(アンダースコア)
を付与することでアクセスをプライベートに限定(=外部に公開しない)ように設定することができます。
class Person {
String name;
int age;
// プライベート変数(外部(=別ファイル)から参照できない)
int _userId;
Person(this.name, this.age, this._userId);
void introduce() {
print("こんにちは、私は$name です。年齢は $age 歳です。");
}
}
ただこの限定はファイル単位ので制御になるので同一ファイル内からは参照できてしまうので注意してください。またこれはプロパティに限った話ではなくクラス名や関数名にも_(アンダースコア)
を付与することでアクセスをプライベートに限定(=外部に公開しない)するように設定することができます。
// 別ファイルからはアクセス不可
class _PrivateClass {
String publicVar = "public";
// 別ファイルからはアクセス不可
String _privateVar = "private";
void publicMethod() {
print("This is a public method");
}
// 別ファイルからはアクセス不可
void _privateMethod() {
print("This is a private method");
}
}
クラス変数
変数の定義にstatic
を付与することでインスタンス化せずとも参照でき、さらに全インスタンスで共有する変数(=クラス変数)として定義することが可能です。
class Person {
// クラス変数
static int population = 0;
Person() {
// インスタンス作成ごとに増加
population++;
}
}
Person p1 = Person();
Person p2 = Person();
print(Person.population); // 2
Named Constructors
通常のコンストラクタだけでなく、任意の名前のコンストラクタを実装することも可能です。これを「Named Constructors」と呼びます。
class Person {
String name;
int age;
Person(this.name, this.age);
// Named Constructors
Person.unknown() {
name = "不明";
age = 0;
}
}
Person p1 = Person.unknown();
print("${p1.name}, ${p1.age}"); // 不明, 0
コンストラクタの種類はたくさんあるので以下の記事がとても参考になりました。
Initializer List
コンストラクタに:
をつけることでコンストラクタ実行前に任意の処理を行わせることが可能です。例えばassert
を使用してバリデーションのように使用したり、任意の計算を行わせてから変数に格納したりなどすることができます。複数の処理を入れ込みたい場合は,
で区切って記述することが可能です。
class Person {
final String name;
final int age;
// Initializer Listを使用してコンストラクタ実行前に処理を実行
Person(this.name, this.age) : assert(age >= 0, "年齢は0以上である必要があります");
}
// クラスのインスタンスを作成
Person p1 = Person("ame", 2);
// Uncaught Error, error: Error: Assertion failed:
Person p2 = Person("ame", -1);
ゲッター・セッター
ゲッター・セッターを実装するためにはget
/set
を使用して以下のように実装できます。
class Person {
String _name; // プライベート変数
Person(this._name);
// ゲッター
String get name => _name;
// セッター
set name(String newName) {
_name = newName;
}
}
var p = Person("田中");
print(p.name); // ゲッター
p.name = "吉田"; // セッター
print(p.name); // 吉田
継承とオーバーライド
クラスにextends
を使用することで別のクラスを継承することができます。継承するとそのクラスの持っているプロパティやメソッドが利用できるようになります。継承したメソッドは@override
を付与することでそのメソッドの内容を上書きすることが可能です。元メソッドの処理も残したい場合はsuper.makeSound()
のように呼び出せます。
class Animal {
void makeSound() {
print("動物の鳴き声");
}
}
class Dog extends Animal {
@override
void makeSound() {
// super.makeSound() // 親のメソッドを呼び出す
print("ワンワン!");
}
}
抽象クラス
class
の前にabstract
を付与すると直接インスタンス化して使用できない抽象クラスになります。抽象クラスは継承させて使用するためのもので複数のクラスで共通した実装をしたい場合に活用できます。
// 抽象クラス
abstract class Animal {
// 抽象メソッド
void makeSound();
}
class Dog extends Animal {
// makeSoundをオーバーライドしないとエラーになる
@override
void makeSound() {
print("ワンワン!");
}
}
class Cat extends Animal {
// makeSoundをオーバーライドしないとエラーになる
@override
void makeSound() {
print("にゃお");
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。