单例模式可确保仅创建一个类的实例。如何在Dart中构建它?
单例模式可确保仅创建一个类的实例。如何在Dart中构建它?
Answers:
多亏了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()
。第二种方法也是如此_instance
。我不知道不使用私有构造函数的不利之处。到目前为止,我还没有发现任何问题。无论如何,第二种方法和第三种方法都不会阻止对默认构造函数的调用。
SingletonThree instance2 = SingletonThree()
。如果在有私有构造函数的情况下尝试执行此操作,则会收到错误:The class 'SingletonThree' doesn't have a default constructor.
我觉得阅读不是很直观new Singleton()
。您必须阅读文档才能知道new
实际上并没有像通常那样创建新实例。
这是做单例的另一种方式(基本上是安德鲁所说的话)。
lib / thing.dart
library thing;
final Thing thing = new Thing._private();
class Thing {
Thing._private() { print('#2'); }
foo() {
print('#3');
}
}
主镖
import 'package:thing/thing.dart';
main() {
print('#1');
thing.foo();
}
请注意,由于Dart的延迟初始化,直到第一次调用getter时才创建单例。
如果愿意,还可以在singleton类上将singletons实现为静态getter。即Thing.singleton
,而不是顶级吸气剂。
还可以从他的《游戏编程模式》一书中阅读鲍勃·尼斯特罗姆(Bob Nystrom)对单例的看法。
像这样在库中使用全局变量呢?
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
隔离中只能存在一个实例。
new Singleton._internal()
根据需要调用任意多次,从而创建了Singleton
该类的许多对象。如果Impl
安德鲁示例中的类为private(_Impl
),则该示例与您的示例相同。另一方面,单例是反模式,任何人都不应使用它。
Singelton._internal()
。您可以辩称,singelton类的开发人员也可以使该类实例化几次。当然有枚举singelton,但对我来说,这仅是理论上的用途。一个枚举是一个枚举,而不是一个singelton ...至于顶级变量(@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}
阅读完所有替代方案后,我想到了这一点,这让我想起了“经典单例”:
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
getInstance
在这样的instance
属性中更改方法:static AccountService get instance => _instance;
这是一个结合其他解决方案的简洁示例。可以通过以下方式访问单例:
singleton
指向实例的全局变量。Singleton.instance
模式。注意:您应该只实现三个选项之一,以使使用单例的代码保持一致。
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
}
你好,这样的事情呢?非常简单的实现,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;
}
}
这应该工作。
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
关键字或其他构造函数(例如对单例的调用),因此我更喜欢使用一个静态的getter 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));