[3分]プリウスとアクアから学ぶFlutterでのシングルトン
はじめに
今までシングルトンを使ったことがなかったので、一度詳しくまとめてみようと思います。
シングルトンの使い方についてざっくりと理解したい方は、プリウスとアクアを使ってシングルトンを体感してみる
から読んでいただくのが良いかなと思います。
シングルトンとは
- シングルトンパターンで実装されたクラスは、実行時に1つしかインスタンスが生成されない
これだけではわかりにくいので、以下に具体例を示します。
ユースケース
- グローバルな状態の管理する場合 => クラス間で共通のメソッド、値にアクセスできる
- 状態(ステート)を持たないことの明示 => 複数のインスタンスを生成する必要がない
- 使用メモリを減らしたい場合(新しいインスタンスのためにメモリを毎回確保する必要がなくなる)
以下では、ユースケースの1つ目のクラス間で共通のメソッド、値にアクセスできる
という性質を例に説明していきます。
普通のクラス
class MyClass{
//...中身
}
final instance1 = MyClass();
final instance2 = MyClass();
instance1
とinstance2
は同一のMyClass
クラスからそれぞれのインスタンスを生成しています。
インスタンスが複数なので、形は同じだが内部の状態(state)は異なるオブジェクトとして扱われます。
シングルトンで実装されたクラス
class Singleton{
//...中身
}
final instance1 = Singleton();
final instance2 = Singleton();
instance1
とinstance2
は同一のSingleton
クラスで同一のインスタンスを参照しています。
同じインスタンスを参照しているので、内部の状態(state)が共通のSingleton
オブジェクトです。
プログラミングを始めたばかりだと、
「同じクラスを呼んでいるんだから、内部の state も共通になってるのでは?」
と思ったりもしますが、普通は違います。
1つのインスタンス毎に 1 つのステートを持ちます。
シングルトンでクラスを実装すれば、どこからSingleton()
を呼んでも同じ内部状態(ステート)になっているわけです。
シングルトンの作り方
Flutter (Dart)でのシングルトンの作り方について説明します。
- コンストラクタ
Singleton._internal()
をプライベート(アンダーバーをつけた状態)にし、外部から呼び出せないように - クラス(static な)変数にインスタンス(
Singleton._internal()
)を格納 - 外部から呼ばれる時には、(プライベートなインスタンスを格納した)クラス変数を返すように
class Singleton{
static final Singleton _instance = Singleton._internal();
factory Singleton(){
return _instance;
}
Singleton._internal();
}
プリウスとアクアを使ってシングルトンを体感してみる
具体例として、プリウス(Prius)君とアクア(Aqua)君に登場してもらいましょう。
普通のクラスPrius
とシングルトンクラスのAqua
にそれぞれオプションをつけるメソッドを用意してやりましょう。
普通のクラス Prius
以下がプリウス君です。
class Prius {
Prius();
List<String> options = [];
List<String> addOption(String option) {
return options..add(option);
}
}
このプリウス君にオプションをつけてやりましょう。
void main() {
final prius1 = Prius();
print(prius1.addOption('カーナビ')); //[カーナビ]
print(prius1.addOption('ドラレコ')); //[カーナビ, ドラレコ]
final prius2 = Prius();
print(prius2.addOption('ヒーター')); //[ヒーター]
}
こちらの例では、同じプリウスでもprius1
とprius2
は違う車になっています。
オプションとしてカーナビ
とドラレコ
をつけた後に、ヒーター
をつけましたが、違う車にそれぞれ取り付けてしまっています。
ここで、シングルトンで作られたアクア君にオプションをつけてやりましょう。
シングルトンクラス Aqua
以下がアクア君です。
class Aqua {
static final Aqua _instance = Aqua._internal();
List<String> options = [];
factory Aqua() {
return _instance;
}
Aqua._internal();
List<String> addOption(String option) {
return options..add(option);
}
}
このアクア君にオプションをつけてやりましょう。
void main() {
final aqua1 = Aqua();
print(aqua1.addOption('カーナビ')); //[カーナビ]
print(aqua1.addOption('ドラレコ')); //[カーナビ, ドラレコ]
final aqua2 = Aqua();
print(aqua2.addOption('ヒーター')); //[カーナビ, ドラレコ, ヒーター]
}
Aqua
はシングルトンクラスなので、aqua1
とaqua2
は同じ車を表しています。
したがって、aqua1
とaqua2
にそれぞれ取り付けたオプションは、全て反映されていますね。
最後に
今回の記事で Flutter でのシングルトンの作り方・使い方は理解できましたか?
シングルトンを使ったことがない方の参考になれば幸いです。
Twitter では Flutter を中心とする技術関連の情報を発信しています!
お仕事の依頼は以下のメールアドレスまでご連絡をよろしくお願いします。
mark.saito@jp-gx.com
Discussion