シングルトンパターンにより、クラスのインスタンスが1つだけ作成されます。これをDartで構築するにはどうすればよいですか?
23 に答える
Dartのファクトリコンストラクターのおかげで、シングルトンを簡単に構築できます。
class Singleton {
static final Singleton _singleton = Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
あなたはそれをこのように構築することができます
main() {
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
これは、Dartでシングルトンを作成するためのいくつかの異なる方法の比較です。
1.ファクトリーコンストラクター
class SingletonOne {
SingletonOne._privateConstructor();
static final SingletonOne _instance = SingletonOne._privateConstructor();
factory SingletonOne() {
return _instance;
}
}
2.ゲッター付き静的フィールド
class SingletonTwo {
SingletonTwo._privateConstructor();
static final SingletonTwo _instance = SingletonTwo._privateConstructor();
static SingletonTwo get instance => _instance;
}
3.静的フィールド
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
インスタンス化する方法
上記のシングルトンは次のようにインスタンス化されます。
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
ノート:
私はもともとこれを質問として尋ねましたが、上記のすべての方法が有効であり、選択は個人の好みに大きく依存することを発見しました。
私はそれが非常に直感的な読書だとは思いませんnew Singleton()
。ドキュメントを読んで、new
通常のように実際に新しいインスタンスが作成されていないことを確認する必要があります。
シングルトンを行う別の方法があります(基本的にアンドリューが上で言ったこと)。
lib / things.dart
library thing;
final Thing thing = new Thing._private();
class Thing {
Thing._private() { print('#2'); }
foo() {
print('#3');
}
}
main.dart
import 'package:thing/thing.dart';
main() {
print('#1');
thing.foo();
}
シングルトンは、ダートの遅延初期化のためにゲッターが最初に呼び出されるまで作成されないことに注意してください。
必要に応じて、シングルトンクラスに静的ゲッターとしてシングルトンを実装することもできます。つまりThing.singleton
、トップレベルのゲッターの代わりに。
また、彼のゲームプログラミングパターンの本からボブナイストロームのシングルトンの見解を読んでください。
簡単な答えは次のとおりです。
まず、クラスタイプのprivate
とプロパティが必要です。static
次に、private
クラスの外部からのオブジェクトの初期化を防ぎたいので、コンストラクターはである必要があります。
最後に、インスタンスのnull可能性を確認します。nullの場合はインスタンス化して返します。それ以外の場合は、すでにインスタンス化されているインスタンスを返します。
遅延読み込みを使用した実装
class Singleton {
static Singleton? _instance;
Singleton._();
static Singleton get instance => _instance ??= Singleton._();
void someMethod(){
...
}
...
}
積極的な読み込みを使用した実装
class Singleton {
static Singleton _instance = Singleton._();
Singleton._();
static Singleton get instance => _instance;
void someMethod(){
...
}
...
}
使用法
Singleton.instance.someMethod();
ライブラリ内でグローバル変数を使用するのはどうですか?
single.dart
:
library singleton;
var Singleton = new Impl();
class Impl {
int i;
}
main.dart
:
import 'single.dart';
void main() {
var a = Singleton;
var b = Singleton;
a.i = 2;
print(b.i);
}
それともこれは眉をひそめていますか?
グローバルの概念が存在しないJavaではシングルトンパターンが必要ですが、Dartでは長い道のりを歩む必要はないようです。
別の可能な方法は次のとおりです。
void main() {
var s1 = Singleton.instance;
s1.somedata = 123;
var s2 = Singleton.instance;
print(s2.somedata); // 123
print(identical(s1, s2)); // true
print(s1 == s2); // true
//var s3 = new Singleton(); //produces a warning re missing default constructor and breaks on execution
}
class Singleton {
static final Singleton _singleton = new Singleton._internal();
Singleton._internal();
static Singleton get instance => _singleton;
var somedata;
}
constコンストラクターとファクトリーによるDartシングルトン
class Singleton {
factory Singleton() =>
Singleton._internal_();
Singleton._internal_();
}
void main() {
print(new Singleton() == new Singleton());
print(identical(new Singleton() , new Singleton()));
}
インスタンス化後にオブジェクトを変更できないシングルトン
class User {
final int age;
final String name;
User({
this.name,
this.age
});
static User _instance;
static User getInstance({name, age}) {
if(_instance == null) {
_instance = User(name: name, age: age);
return _instance;
}
return _instance;
}
}
print(User.getInstance(name: "baidu", age: 24).age); //24
print(User.getInstance(name: "baidu 2").name); // is not changed //baidu
print(User.getInstance()); // {name: "baidu": age 24}
この例では、シングルトンを使用したいときにも必要な他のことを行います。例えば:
- シングルトンのコンストラクターに値を渡します
- コンストラクター自体の内部で値を初期化します
- シングルトンの変数に値を設定します
- これらの値にアクセスおよびアクセスできる。
このような:
class MySingleton {
static final MySingleton _singleton = MySingleton._internal();
String _valueToBeSet;
String _valueAlreadyInSingleton;
String _passedValueInContructor;
get getValueToBeSet => _valueToBeSet;
get getValueAlreadyInSingleton => _valueAlreadyInSingleton;
get getPassedValueInConstructor => _passedValueInContructor;
void setValue(newValue) {
_valueToBeSet = newValue;
}
factory MySingleton(String passedString) {
_singleton._valueAlreadyInSingleton = "foo";
_singleton._passedValueInContructor = passedString;
return _singleton;
}
MySingleton._internal();
}
MySingletonの使用法:
void main() {
MySingleton mySingleton = MySingleton("passedString");
mySingleton.setValue("setValue");
print(mySingleton.getPassedValueInConstructor);
print(mySingleton.getValueToBeSet);
print(mySingleton.getValueAlreadyInSingleton);
}
すべての選択肢を読んだ後、私はこれを思いつきました。これは「クラシックシングルトン」を思い出させます。
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
バージョン以来、キーワードDart 2.13
でとても簡単です。キーワードを使用すると、オブジェクトを遅延インスタンス化できます。late
Late
例として、あなたはそれを見ることができます:
class LazySingletonExample {
LazySingletonExample._() {
print('instance created.');
}
static late final LazySingletonExample instance = LazySingletonExample._();
}
instance
注:レイジーフィールドを呼び出すと、インスタンス化されるのは1回だけであることに注意してください。
これは、他のソリューションを組み合わせた簡潔な例です。シングルトンへのアクセスは、次の方法で実行できます。
singleton
インスタンスを指すグローバル変数を使用します。- 一般的な
Singleton.instance
パターン。 - インスタンスを返すファクトリであるデフォルトのコンストラクタを使用します。
注:シングルトンを使用するコードに一貫性を持たせるために、3つのオプションのうち1つだけを実装する必要があります。
Singleton get singleton => Singleton.instance;
ComplexSingleton get complexSingleton => ComplexSingleton._instance;
class Singleton {
static final Singleton instance = Singleton._private();
Singleton._private();
factory Singleton() => instance;
}
class ComplexSingleton {
static ComplexSingleton _instance;
static ComplexSingleton get instance => _instance;
static void init(arg) => _instance ??= ComplexSingleton._init(arg);
final property;
ComplexSingleton._init(this.property);
factory ComplexSingleton() => _instance;
}
複雑な初期化を行う必要がある場合は、プログラムの後半でインスタンスを使用する前に行う必要があります。
例
void main() {
print(identical(singleton, Singleton.instance)); // true
print(identical(singleton, Singleton())); // true
print(complexSingleton == null); // true
ComplexSingleton.init(0);
print(complexSingleton == null); // false
print(identical(complexSingleton, ComplexSingleton())); // true
}
次のようなシングルトンのSwiftスタイルを好む人のために@SethLaddの回答を変更しました.shared
。
class Auth {
// singleton
static final Auth _singleton = Auth._internal();
factory Auth() => _singleton;
Auth._internal();
static Auth get shared => _singleton;
// variables
String username;
String password;
}
サンプル:
Auth.shared.username = 'abc';
これが私のプロジェクトにシングルトンを実装する方法です
フラッターファイアベースからインスピレーションを受けた=>FirebaseFirestore.instance.collection('collectionName')
class FooAPI {
foo() {
// some async func to api
}
}
class SingletonService {
FooAPI _fooAPI;
static final SingletonService _instance = SingletonService._internal();
static SingletonService instance = SingletonService();
factory SingletonService() {
return _instance;
}
SingletonService._internal() {
// TODO: add init logic if needed
// FOR EXAMPLE API parameters
}
void foo() async {
await _fooAPI.foo();
}
}
void main(){
SingletonService.instance.foo();
}
私のプロジェクトの例
class FirebaseLessonRepository implements LessonRepository {
FirebaseLessonRepository._internal();
static final _instance = FirebaseLessonRepository._internal();
static final instance = FirebaseLessonRepository();
factory FirebaseLessonRepository() => _instance;
var lessonsCollection = fb.firestore().collection('lessons');
// ... other code for crud etc ...
}
// then in my widgets
FirebaseLessonRepository.instance.someMethod(someParams);
状態管理にFlutterとprovider
パッケージを使用している場合、シングルトンの作成と使用は非常に簡単です。
- インスタンスを作成する
void main() { runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (context) => SomeModel()), Provider(create: (context) => SomeClassToBeUsedAsSingleton()), ], child: MyApp(), ), ); }
- インスタンスを取得する
Widget build(BuildContext context) { var instance = Provider.of<SomeClassToBeUsedAsSingleton>(context); ...
これは機能するはずです。
class GlobalStore {
static GlobalStore _instance;
static GlobalStore get instance {
if(_instance == null)
_instance = new GlobalStore()._();
return _instance;
}
_(){
}
factory GlobalStore()=> instance;
}
キーワードやシングルトンの呼び出しのような他のコンストラクターを使用するのはあまり好きではないので、たとえば次new
のような静的ゲッターを使用したいと思います。inst
// the singleton class
class Dao {
// singleton boilerplate
Dao._internal() {}
static final Dao _singleton = new Dao._internal();
static get inst => _singleton;
// business logic
void greet() => print("Hello from singleton");
}
使用例:
Dao.inst.greet(); // call a method
// Dao x = new Dao(); // compiler error: Method not found: 'Dao'
// verify that there only exists one and only one instance
assert(identical(Dao.inst, Dao.inst));
こんにちは、このようなものはどうですか?非常に単純な実装であり、Injector自体はシングルトンであり、クラスも追加されています。もちろん、非常に簡単に拡張できます。より洗練されたものをお探しの場合は、このパッケージを確認してください:https ://pub.dartlang.org/packages/flutter_simple_dependency_injection
void main() {
Injector injector = Injector();
injector.add(() => Person('Filip'));
injector.add(() => City('New York'));
Person person = injector.get<Person>();
City city = injector.get<City>();
print(person.name);
print(city.name);
}
class Person {
String name;
Person(this.name);
}
class City {
String name;
City(this.name);
}
typedef T CreateInstanceFn<T>();
class Injector {
static final Injector _singleton = Injector._internal();
final _factories = Map<String, dynamic>();
factory Injector() {
return _singleton;
}
Injector._internal();
String _generateKey<T>(T type) {
return '${type.toString()}_instance';
}
void add<T>(CreateInstanceFn<T> createInstance) {
final typeKey = _generateKey(T);
_factories[typeKey] = createInstance();
}
T get<T>() {
final typeKey = _generateKey(T);
T instance = _factories[typeKey];
if (instance == null) {
print('Cannot find instance for type $typeKey');
}
return instance;
}
}
** Dart SoundNullSafetyのSigletonパラダイム**
このコードスニペットは、dartにシングルトンを実装する方法を示しています。これは、たとえば、クラスの同じオブジェクトを毎回使用する必要がある状況で一般的に使用されます。データベーストランザクションで。
class MySingleton {
static MySingleton? _instance;
MySingleton._internal();
factory MySingleton() {
if (_instance == null) {
_instance = MySingleton._internal();
}
return _instance!;
}
}
私はこの単純なパターンをダーツと以前はSwiftで使用しました。私はそれが簡潔であり、それを使用する唯一の方法であることが好きです。
class Singleton {
static Singleton shared = Singleton._init();
Singleton._init() {
// init work here
}
void doSomething() {
}
}
Singleton.shared.doSomething();
これは、シングルトンクラスを作成する方法でもあります
class Singleton{
Singleton._();
static final Singleton db = Singleton._();
}
Singleton
nullの安全演算子とファクトリコンストラクタを使用すると、オブジェクトをより適切に作成できます。
class Singleton {
static Singleton? _instance;
Singleton._internal();
factory Singleton() => _instance ??= Singleton._internal();
void someMethod() {
print("someMethod Called");
}
}
使用法:
void main() {
Singleton object = Singleton();
object.someMethod(); /// Output: someMethod Called
}
注: ??
はNull対応の演算子です。左側の値がnullの場合、右側の値を返します。つまり、この例_instance ?? Singleton._internal();
でSingleton._internal()
は、オブジェクトが呼び出されたときに最初に返され、rest_instance
が返されます。
Constantコンストラクターを使用できます。
class Singleton {
const Singleton(); //Constant constructor
void hello() { print('Hello world'); }
}
例:
Singleton s = const Singleton();
s.hello(); //Hello world
ドキュメントによると:
定数コンストラクター
クラスが変更されないオブジェクトを生成する場合は、これらのオブジェクトをコンパイル時定数にすることができます。これを行うには、constコンストラクターを定義し、すべてのインスタンス変数がfinalであることを確認します。