質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

1027閲覧

Dartにおけるシングルトンクラスの作り方につきまして

mako_0221

総合スコア87

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2023/01/24 13:43

編集2023/01/24 13:44

■利用しているDartのバージョン
Dart ver: v3.56.0

■概要
これまであまりクラスのデザインパターン等を意識して利用したことがなかったのですが、sqlliteというパッケージを学んでいる際に以下のようなコードに出会いました。勉強の参考にさせていただいたQiitaの記事はこちらです。
static_createInstance()周りのコードが理解できずに調べているとこれはおそらくシングルトンというクラスを作りたいのかというところに行きつきました。

ともすると、一つわからない点が生じるのですが、Dart-シングルトンの組み合わせで学んでいると、クラス内でインスタンスを生成しそのインスタンスを同じクラス内でfactory Singleton(){ return _instance;}のようにfactory constructorを利用しているようですが、そのようなコードは見たりません。

その一方で、DbHelper._createInstance(); //???のように何らかのコンストラクタを呼び出しているようにも見えます。

■ご質問

  1. このコードはそもそもデザインパターンでいうシングルトンクラスを作ろうとしている理解であっていますか?
  2. そうであるとしたら、なぜ一般的なfactoryコンストラクタを使わずにこのような記述になっているのでしょうか(シンタックスシュガーか何かでしょうか?
  3. そうでないとしたら、どのようなデザインパターンの視点でこのコードを学べば良いのでしょうか?

よろしくお願い申し上げます。

Dart

1import 'package:flutter_crud/model/cats.dart'; 2import 'package:path/path.dart'; 3import 'package:sqflite/sqflite.dart'; 4 5// catsテーブルのカラム名を設定 6const String columnId = '_id'; 7const String columnName = 'name'; 8const String columnGender = 'gender'; 9const String columnBirthday = 'birthday'; 10const String columnMemo = 'memo'; 11const String columnCreatedAt = 'createdAt'; 12 13// catsテーブルのカラム名をListに設定 14const List<String> columns = [ 15 columnId, 16 columnName, 17 columnGender, 18 columnBirthday, 19 columnMemo, 20 columnCreatedAt, 21]; 22 23// catsテーブルへのアクセスをまとめたクラス 24class DbHelper { 25 // DbHelperをinstance化する 26 static final DbHelper instance = DbHelper._createInstance(); 27 static Database? _database; 28 29 DbHelper._createInstance(); //??? 30 31 // databaseをオープンしてインスタンス化する 32 Future<Database> get database async { 33 return _database ??= await _initDB(); // 初回だったら_initDB()=DBオープンする 34 } 35 36 // データベースをオープンする 37 Future<Database> _initDB() async { 38 String path = join(await getDatabasesPath(), 'cats.db'); // cats.dbのパスを取得する 39 40 return await openDatabase( 41 path, 42 version: 1, 43 onCreate: _onCreate, // cats.dbがなかった時の処理を指定する(DBは勝手に作られる) 44 ); 45 } 46 47 // データベースがなかった時の処理 48 Future _onCreate(Database database, int version) async { 49 //catsテーブルをcreateする 50 await database.execute(''' 51 CREATE TABLE cats( 52 _id INTEGER PRIMARY KEY AUTOINCREMENT, 53 name TEXT, 54 gender TEXT, 55 birthday TEXT, 56 memo TEXT, 57 createdAt TEXT 58 ) 59 '''); 60 } 61 62 // catsテーブルのデータを全件取得する 63 Future<List<Cats>> selectAllCats() async { 64 final db = await instance.database; 65 final catsData = await db.query('cats'); // 条件指定しないでcatsテーブルを読み込む 66 67 return catsData.map((json) => Cats.fromJson(json)).toList(); // 読み込んだテーブルデータをListにパースしてreturn 68 } 69 70// _idをキーにして1件のデータを読み込む 71 Future<Cats> catData(int id) async { 72 final db = await instance.database; 73 var cat = []; 74 cat = await db.query( 75 'cats', 76 columns: columns, 77 where: '_id = ?', // 渡されたidをキーにしてcatsテーブルを読み込む 78 whereArgs: [id], 79 ); 80 return Cats.fromJson(cat.first); // 1件だけなので.toListは不要 81 } 82 83// データをinsertする 84 Future insert(Cats cats) async { 85 final db = await database; 86 return await db.insert( 87 'cats', 88 cats.toJson() // cats.dartで定義しているtoJson()で渡されたcatsをパースして書き込む 89 ); 90 } 91 92// データをupdateする 93 Future update(Cats cats) async { 94 final db = await database; 95 return await db.update( 96 'cats', 97 cats.toJson(), 98 where: '_id = ?', // idで指定されたデータを更新する 99 whereArgs: [cats.id], 100 ); 101 } 102 103// データを削除する 104 Future delete(int id) async { 105 final db = await instance.database; 106 return await db.delete( 107 'cats', 108 where: '_id = ?', // idで指定されたデータを削除する 109 whereArgs: [id], 110 ); 111 } 112}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

このコードはそもそもデザインパターンでいうシングルトンクラスを作ろうとしている理解であっていますか?

そう考えてもいいと思います。

そうであるとしたら、なぜ一般的なfactoryコンストラクタを使わずにこのような記述になっているのでしょうか(シンタックスシュガーか何かでしょうか?

名前付きのコンストラクタ、この場合はDbHelper._createInstance()になりますが、これを書くことでフォルトコンストラクタDbHelper()での呼び出しができないようにしています。また_を付けることでプライベート化するので、外部からのインスタンス生成ができなくなります。

factoryで書くことも可能だけど、それだと若干実装行数が増えるのでこのような形にしたのではないでしょうか。

https://gist.github.com/AbedElazizShe/2817592ce7d2070c5a0d1c73a220e85a
こっちがfactoryで書いた例になるのかな。

投稿2023/01/25 00:47

ta.fu

総合スコア1667

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mako_0221

2023/01/26 06:14

ありがとうございます、いずれの方法でもできるが簡便的な実装方法によっているという理解をいたしました。 大変申し訳ないのですが、どうしても調べても以下の点にピント来ないのですが static Dbhelper instance = Dbhelper._createInstance();//(1) Dbhelper._createInstance(); //(2) (2)で名前付きコンストラクタが実行される (1)で同じように名前付きコンストラクタだ実行されてinstance変数に格納されている ということなのかと推察していますが、instanceに入れることは別として、 Dbhelper._createInstance()が2回実行されるのはここでは直感的にどのようにとらえればよいのでしょうか?
ta.fu

2023/01/26 07:11

2回実行されているわけではありません。 (1)の方はDbhelperのインスタンスを作りそれを代入。 (2)は名前付きコンストラクタの定義です。 コンストラクタは{}が付いたファンクションボディと呼ばれる定義と;のみの定義ができます。 ;の場合は{}と同等(仕様上はempty body {}と書いてある)と認識されます。 Dart2.10仕様書の10及び10.6.1に記載があります。 あと、意味は書いてないけど、 https://dart.dev/guides/language/language-tour#constructors のPointに;で終わるコンストラクタが書いてあります。
mako_0221

2023/01/26 08:14

ありがとうございます! (1)の方はDbhelperのインスタンスを作りそれを代入。の「それ」とは何を指しているのでしょうか?定義した名前付きコンストラクタを差していると思っていいのでしょうか? また、2回実行されていないとしたら、1回実行されているとしたら(1)で実行されていて、実行された結果がinstanceに格納されているイメージであっていますか? 分かりづらい表現で申し訳ございません。
ta.fu

2023/01/26 08:32

「それ」は「インスタンス」のことです。 DbhelperのインスタンスをDbhelper._createInstance()で作成し、そのインスタンスを変数instanceに代入する。 (1)の部分は、上記の様な処理になるということです。
mako_0221

2023/01/26 15:57

ありがとうございます。 最後に念の為の確認ですが、(1)のDbhelper._createInstance()でインスタンスを作成して、変数に格納していることはわかったのですが、(2)のDbhelper._createInstance()はインスタンスの作成はしておらず、単なる名前付きコンストラクタの定義と認識して差し支えないでしょうか?
ta.fu

2023/01/26 23:21

そうです。
mako_0221

2023/01/27 01:01

最後までありがとうございます。まだ少し記述の方法として、直感的になるほどというところまで腹落ちはしていないのですが、漠然と意味がわからないコードについて、何をしたいのかは理解できました。 お力添えに御礼申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問