Mẫu singleton đảm bảo chỉ có một phiên bản của một lớp được tạo. Làm thế nào để tôi xây dựng điều này trong Dart?
Mẫu singleton đảm bảo chỉ có một phiên bản của một lớp được tạo. Làm thế nào để tôi xây dựng điều này trong Dart?
Câu trả lời:
Cảm ơn các nhà xây dựng nhà máy của Dart , thật dễ dàng để xây dựng một singleton:
class Singleton {
static final Singleton _singleton = Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
Bạn có thể xây dựng nó như thế này
main() {
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
new
không có nghĩa là "xây dựng một cái mới" ở đây, nó chỉ nói "chạy hàm tạo".
new
từ khóa gợi ý rằng lớp được khởi tạo, mà nó không phải là. Tôi sẽ dùng một phương thức tĩnh get()
hoặc getInstance()
giống như tôi làm trong Java.
Singleton._internal();
trông giống như một cuộc gọi phương thức khi nó thực sự là một định nghĩa hàm tạo. Có _internal
tên. Và có một điểm thiết kế ngôn ngữ tiện lợi mà Dart cho phép bạn bắt đầu (phóng ra?) Bằng cách sử dụng một hàm tạo thông thường và sau đó, nếu cần, hãy thay đổi nó thành một factory
phương thức mà không thay đổi tất cả người gọi.
Dưới đây là so sánh một số cách khác nhau để tạo ra một singleton trong 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();
}
Các singletons ở trên được khởi tạo như thế này:
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
Ghi chú:
Ban đầu tôi đã hỏi điều này như một câu hỏi , nhưng phát hiện ra rằng tất cả các phương pháp trên đều hợp lệ và sự lựa chọn chủ yếu phụ thuộc vào sở thích cá nhân.
static final SingletonThree instance = SingletonThree()
. Cùng đi đến cách thứ hai cho _instance
. Tôi không biết những bất lợi của việc không sử dụng một nhà xây dựng tư nhân. Cho đến nay, tôi không tìm thấy bất kỳ vấn đề theo cách của tôi. Cách thứ hai và thứ ba không chặn cuộc gọi đến hàm tạo mặc định.
SingletonThree instance2 = SingletonThree()
. Nếu bạn cố gắng làm điều này khi có một nhà xây dựng tư nhân, bạn sẽ nhận được lỗi:The class 'SingletonThree' doesn't have a default constructor.
Tôi không thấy nó đọc rất trực quan new Singleton()
. Bạn phải đọc các tài liệu để biết rằng new
thực tế không tạo ra một thể hiện mới, như thường lệ.
Đây là một cách khác để làm singletons (Về cơ bản những gì Andrew đã nói ở trên).
lib / điều.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();
}
Lưu ý rằng singleton không được tạo cho đến lần đầu tiên getter được gọi do khởi tạo lười biếng của Dart.
Nếu bạn thích, bạn cũng có thể triển khai singletons dưới dạng getter tĩnh trên lớp singleton. tức là Thing.singleton
, thay vì một getter cấp cao nhất.
Đồng thời đọc Bob Nystrom tham gia các singletons từ cuốn sách mô hình lập trình trò chơi của anh ấy .
Điều gì về việc chỉ sử dụng một biến toàn cục trong thư viện của bạn, như vậy?
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);
}
Hay điều này là nhíu mày?
Mẫu đơn là cần thiết trong Java, nơi khái niệm toàn cầu không tồn tại, nhưng có vẻ như bạn không cần phải đi một chặng đường dài trong Dart.
Singleton
dễ dàng truy cập. Trong ví dụ của tôi ở trên, Singleton
lớp là một singleton thực sự, chỉ có một trường hợp duy nhất Singleton
có thể tồn tại trong sự cô lập.
new Singleton._internal()
bao nhiêu lần tùy ý, tạo ra rất nhiều đối tượng của Singleton
lớp. Nếu Impl
lớp trong ví dụ của Andrew là private ( _Impl
), thì nó sẽ giống như ví dụ của bạn. Mặt khác, singleton là một antipotype và dù sao cũng không nên sử dụng nó.
Singelton._internal()
. Bạn có thể lập luận rằng các nhà phát triển của lớp singelton cũng có thể tạo ra lớp này nhiều lần. Chắc chắn là có enumton enumton nhưng với tôi nó chỉ là sử dụng lý thuyết. Một enum là một enum, không phải là một singelton ... Đối với việc sử dụng các biến cấp cao nhất (@Andrew và @Seth): Không ai có thể ghi vào biến cấp cao nhất? Đó không phải là được bảo vệ, hoặc tôi đang thiếu một cái gì đó?
Đây là một cách có thể khác:
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;
}
Đơn vị phi tiêu bởi const constructor & nhà máy
class Singleton {
factory Singleton() =>
const Singleton._internal_();
const Singleton._internal_();
}
void main() {
print(new Singleton() == new Singleton());
print(identical(new Singleton() , new Singleton()));
}
Ví dụ như Singleton không thể thay đổi đối tượng
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}
Câu trả lời @Seth Ladd đã sửa đổi cho những người thích phong cách singleton của Swift như .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;
}
Mẫu vật:
Auth.shared.username = 'abc';
Sau khi đọc tất cả các lựa chọn thay thế, tôi đã nghĩ ra cái này, nó gợi cho tôi một "singleton cổ điển":
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
getInstance
phương thức trong một thuộc instance
tính như thế này:static AccountService get instance => _instance;
Đây là một ví dụ ngắn gọn kết hợp các giải pháp khác. Truy cập singleton có thể được thực hiện bằng cách:
singleton
biến toàn cục trỏ đến thể hiện.Singleton.instance
mô hình phổ biến .Lưu ý: Bạn chỉ nên thực hiện một trong ba tùy chọn để mã sử dụng singleton phù hợp.
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;
}
Nếu bạn cần thực hiện khởi tạo phức tạp, bạn sẽ phải làm như vậy trước khi sử dụng ví dụ sau trong chương trình.
Thí dụ
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
}
Xin chào, những gì như thế này? Thực hiện rất đơn giản, Injection chính nó là singleton và cũng đã thêm các lớp vào nó. Tất nhiên có thể được mở rộng rất dễ dàng. Nếu bạn đang tìm kiếm thứ gì đó tinh vi hơn, hãy kiểm tra gói này: 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;
}
}
Điều này nên làm việc.
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._();
sẽ làm. Phải _(){}
làm gì đây? Điều này có vẻ dư thừa.
Vì tôi không thích sử dụng new
từ khóa hoặc hàm tạo khác như các cuộc gọi trên singletons, tôi thích sử dụng một getter tĩnh được gọi là inst
ví dụ:
// 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");
}
sử dụng ví dụ:
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));