单例模式确保只创建一个类的实例。我如何在达特建立这个?


当前回答

这就是我如何在我的项目中实现单例

灵感来自flutter firebase => 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);

其他回答

在Dart中创建Singleton没有什么棘手的。您可以在顶级(全局)位置声明任何变量,默认情况下这是一个单例。也可以将变量声明为类的静态成员。这是单元素a。

class A {}

final a = A();

However, the above does not allow you to replace the instance for testing. The other issue is that as the app grows in complexity, you may want to convert global or static variables to transient dependencies inside your classes. If you use dependency injection, you can change a dependency inside your composition at any time. This is an example of using ioc_container to configure a singleton instance of A in the root of an app. You can change this to a transient dependency any time by using add instead of addSingletonService

import 'package:ioc_container/ioc_container.dart';

class A {}

void main(List<String> arguments) {
  final builder = IocContainerBuilder()..addSingletonService(A());
  final container = builder.toContainer();
  final a1 = container<A>();
  final a2 = container<A>();
  print(identical(a1, a2));
}

上面打印为真,因为应用程序只会生成一个A实例。

这是另一种可能的方式:

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 PermissionSettingService {
  static PermissionSettingService _singleton = PermissionSettingService._internal();

  factory PermissionSettingService() {
    return _singleton;
  }

  PermissionSettingService._internal();
}

重置单例

// add this function inside the function
  void reset() {
   _singleton = PermissionSettingService._internal();
  }

我觉得阅读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的惰性初始化,直到第一次调用getter时才创建单例。

如果你愿意,你也可以在单例类上作为静态getter来实现单例。即的事情。单例,而不是顶级getter。

还可以阅读Bob Nystrom在他的游戏编程模式书中对单身人士的看法。

这是我做单例的方式,接受参数(你可以直接粘贴到https://dartpad.dev/):

void main() {
  
  Logger x = Logger('asd');
  Logger y = Logger('xyz');
  
  x.display('Hello');
  y.display('Hello There');
}


class Logger{
  
  
  Logger._(this.message);
  final String message;
  static Logger _instance = Logger._('??!?*');
  factory Logger(String message){
    if(_instance.message=='??!?*'){
      _instance = Logger._(message);
    }
    return _instance;
  }
  
  void display(String prefix){
    print(prefix+' '+message);
  }
  
}

输入:

Hello asd
Hello There asd

“? ? ! ?*'你看到的只是一个工作区,我做了初始化_instance变量暂时没有使它成为一个Logger?类型(空安全)。