回答:
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
}
new
かもしれませんが、ここでは「新しいコンストラクタを作成する」という意味ではなく、「コンストラクタを実行する」とだけ言っています。
new
キーワードは、それがされていない、クラスをインスタンス化することを示唆しています。私は、静的メソッドのために行くだろうget()
か、getInstance()
私はJavaで行うように。
Singleton._internal();
それが実際にコンストラクター定義である場合、メソッド呼び出しのように見える奇妙な構文があります。_internal
名前があります。そして、Dartが通常のコンストラクターを使用して開始(dart out?)し、必要に応じて、factory
すべての呼び出し元を変更せずにメソッドに変更できる、気の利いた言語設計ポイントがあります。
Dartでシングルトンを作成するいくつかの異なる方法の比較を以下に示します。
class SingletonOne {
SingletonOne._privateConstructor();
static final SingletonOne _instance = SingletonOne._privateConstructor();
factory SingletonOne() {
return _instance;
}
}
class SingletonTwo {
SingletonTwo._privateConstructor();
static final SingletonTwo _instance = SingletonTwo._privateConstructor();
static SingletonTwo get instance => _instance;
}
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
上記のシングルトンは次のようにインスタンス化されます。
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
注意:
私はもともとこれを質問として尋ねましたが、上記の方法はすべて有効であり、選択は個人の好みに大きく依存することがわかりました。
static final SingletonThree instance = SingletonThree()
。同じことがの2番目の方法にも当てはまり_instance
ます。プライベートコンストラクターを使用しないことの欠点は何ですか。これまでのところ、問題はありません。2番目と3番目の方法は、いずれにしてもデフォルトのコンストラクターへの呼び出しをブロックしていません。
SingletonThree instance2 = SingletonThree()
。プライベートコンストラクタがある場合には、あなたがこれを行うにしようとすると、エラーになります:The class 'SingletonThree' doesn't have a default constructor.
直感的に読めないnew Singleton()
。あなたはそれを知るためにドキュメントを読む必要がありますnew
それが通常のように実際に新しいインスタンスを作成していないは。
シングルトンを実行する別の方法を以下に示します(基本的に、Andrewが上で言ったこと)。
lib / thing.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();
}
シングルトンは、Dartの遅延初期化により、最初にゲッターが呼び出されるまで作成されないことに注意してください。
必要に応じて、シングルトンクラスの静的ゲッターとしてシングルトンを実装することもできます。すなわちThing.singleton
、トップレベルのゲッターの代わりに。
また、彼のゲームプログラミングパターンの本から、ボブニストロムのシングルトンへの取り組みを読んでください。
ライブラリ内でグローバル変数を使用するだけではどうですか?
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で長い時間を費やす必要はないようです。
Singleton
にアクセスしやすくするために、トップレベルの変数を正しく使用しました。上記の私の例では、Singleton
クラスは実際のシングルトンSingleton
です。分離内に存在できるインスタンスは1つだけです。
new Singleton._internal()
だけ何度でも呼び出すことができ、Singleton
クラスの多くのオブジェクトを作成します。場合はImpl
アンドリューの例ではクラスが(プライベートだった_Impl
)、それはあなたの例と同じになります。一方、シングルトンはアンチパターンであり、誰もがそれを使用するべきではありません。
Singelton._internal()
。singeltonクラスの開発者は、クラスを数回インスタンス化することもできると主張できます。確かにenum singeltonはありますが、私にはそれは理論的にのみ使用されます。enumはsingeltonではなくenumです...トップレベルの変数(@Andrewと@Seth)の使用については:誰もトップレベルの変数に書き込むことができませんでしたか?それは決して保護されていません、または私は何かを逃していますか?
これは別の可能な方法です:
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;
}
インスタンス後にオブジェクトを変更できないシングルトン
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, idade: 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}
以下のようなシングルトンのSwiftスタイルを好む人のために@Seth Laddの回答を変更しました.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';
すべての代替案を読んだ後、私はこれを思い付きました。これは「クラシックシングルトン」を思い出させます。
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
getInstance
メソッドを変更しinstance
ます:static AccountService get instance => _instance;
以下は、他のソリューションを組み合わせた簡潔な例です。シングルトンへのアクセスは、次の方法で実行できます。
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
}
こんにちは、このようなものはどうですか?インジェクター自体は非常にシンプルな実装であり、シングルトンであり、それにクラスも追加されています。もちろん、非常に簡単に拡張できます。もっと洗練されたものを探しているなら、このパッケージをチェックしてください: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;
}
}
これはうまくいくはずです。
class GlobalStore {
static GlobalStore _instance;
static GlobalStore get instance {
if(_instance == null)
_instance = new GlobalStore()._();
return _instance;
}
_(){
}
factory GlobalStore()=> instance;
}
static GlobalStore get instance => _instance ??= new GlobalStore._();
するだろう。何を_(){}
すべきか?これは冗長なようです。
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));