タイトルを見て内容を察した方は読み飛ばして下さい。(もし分からなかった方だけお読み下さい)
いきなり例え話から入りますが、以下のコード(強調されている行)を見て下さい。
(これはSQLite操作の為の、Database_Helper.dartというソースファイルの抜粋です)
class DBHelper {
static final DBHelper _instance = DBHelper._internal();
factory DBHelper() => _instance;
DBHelper._internal();
Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
6行目で、
Database? _database;
と宣言しているが分かりますよね。これ(_database)はプライベートなデータとして扱うよ、という意味です。
そのすぐ下(8行目)で、
Future get database async {
とメソッドが定義されていますよね。この(database)は外部に公開されるよ、という意味です。
しかしメソッド内部では、上記で宣言したプライベートなデータ(_database)を扱っています。
これを見て、なんでだろう、と思う方に、
結論を言ってしまうと、上記の _database と database の扱いは正しく問題はありません。
説明が遅れましたが、上記のメソッドは、getter メソッド と言われる一般的なメソッドです。
以下は、getter メソッドの説明になります。
1.なぜ getter メソッドを使用するのか
上記で言った通り、上記の _database と database の扱いについては、問題ありません。
ここで使用されているのは Dart の言語機能で、具体的には getter メソッドの定義を利用しています。
_database はプライベートな変数で、クラス内部のみからアクセス可能です。
一方、database は公開された getter メソッドで、このメソッドを通じて _database の値を外部から安全に取得できます。
以下はgetterメソッドを使用する理由です。
(1) 遅延初期化
_database は最初に null であり、データベースへの接続が必要になった時点で初めて初期化されます。
このパターンを使用すると、アプリの起動時にデータベースへの接続が不要な場合、リソースを節約できます。
(2) エンカプセレーションの強化
プライベート変数 _databaseを直接公開する代わりに、getter メソッドを通じて提供することで、変数へのアクセスを制御し、クラスの振る舞いをより詳細に管理できます。
例えば、database が null の場合にのみデータベースを初期化するというロジックを database getter 内にカプセル化しています。
Database? _database;
Future<Database> get database async {
if (_database != null) return _database!; // 既に_databaseが初期化されていればそれを返す
_database = await _initDatabase(); // 未初期化の場合、データベースを初期化
return _database!; // 初期化されたデータベースを返す
}
このコードは、_database 変数が null であるかどうかをチェックし、null の場合は _initDatabase() メソッドを呼び出してデータベースを非同期に初期化します。
初期化後、または _database が既に初期化されている場合は、_database! を返します
( ! は null 安全のための Dart の非 null アサーション演算子です)。
上記により、安全性を確保するために、getter メソッドを使用する、ということが分かりました。
では、実用性についてはどうでしょうか?
2.実用性
上記のような設計は、Dart の null 安全機能を活用しており、データベース接続の遅延初期化を効率的に行うことができます。
加えて、データベースのハンドルを要求するすべての操作で database getter を使用することにより、データベース接続の管理が一元化され、コードの整理と保守が容易になります。
このような理由で、getter というメソッドが良く使用されています。