web-dev-qa-db-ja.com

Dartでシングルトンをどのように構築しますか?

シングルトンパターンは、クラスの1つのインスタンスのみが作成されるようにします。これをDartでビルドするにはどうすればよいですか?

122
Seth Ladd

Dartの factory constructors のおかげで、シングルトンを簡単に構築できます。

class Singleton {
  static final Singleton _singleton = new Singleton._internal();

  factory Singleton() {
    return _singleton;
  }

  Singleton._internal();
}

newで構築できます

main() {
  var s1 = new Singleton();
  var s2 = new Singleton();
  print(identical(s1, s2));  // true
  print(s1 == s2);           // true
}
190
Seth Ladd

以下は、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 { return _instance;}

}

3.静的フィールド

class SingletonThree {

  SingletonThree._privateConstructor();

  static final SingletonThree instance = SingletonThree._privateConstructor();

}

インスタンス化する方法

上記のシングルトンは次のようにインスタンス化されます。

SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;

注:

私はもともとこれを question として尋ねましたが、上記の方法はすべて有効であり、選択は個人の好みに大きく依存することがわかりました。

44
Suragch

new Singleton()を非常に直感的に読むことはできません。 newは通常のように実際に新しいインスタンスを作成していないことを知るためにドキュメントを読む必要があります。

シングルトンを実行する別の方法を次に示します(基本的にアンドリューが言ったこと)。

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の遅延初期化により、getterが最初に呼び出されるまでシングルトンは作成されないことに注意してください。

必要に応じて、シングルトンクラスの静的ゲッターとしてシングルトンを実装することもできます。つまりThing.singleton、トップレベルのゲッターの代わりに。

また、ボブ・ナイストロムの取り組み 彼のゲームプログラミングパターンの本からのシングルトン も読んでください。

32
Greg Lowe

ライブラリ内でグローバル変数を使用するのはどうですか?

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で長い道のりを歩む必要はないようです。

12
Andrew Gerrand

別の可能な方法を次に示します。

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;
}
9
iBob101

ConstコンストラクターとファクトリーによるDartシングルトン

class Singleton {
  factory Singleton() =>
    const Singleton._internal_();
  const Singleton._internal_();
}


void main() {
  print(new Singleton() == new Singleton());
  print(identical(new Singleton() , new Singleton()));
}
9
Ticore Shih

好きな人の@Seth Laddの回答を修正Swiftのようなシングルトンのスタイル.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';
2
DazChong

インスタンスの後にオブジェクトを変更できないシングルトン

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}
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
}
1
Jacob Phillips

こんにちは、このようなものはどうですか?非常に単純な実装、インジェクター自体はシングルトンであり、クラスも追加されています。もちろん、非常に簡単に拡張できます。もっと洗練されたものを探しているなら、このパッケージをチェックしてください: 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;
  }
}
0
Filip Jerga

これは動作するはずです。

class GlobalStore {
    static GlobalStore _instance;
    static GlobalStore get instance {
       if(_instance == null)
           _instance = new GlobalStore()._();
       return _instance;
    }

    _(){

    }
    factory GlobalStore()=> instance;


}
0
Vilsad P P

私は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));
0
sprestel