답변:
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
이름은. 그리고 다트가 일반적인 생성자를 사용하여 시작하고 (다트 아웃?) 필요한 경우 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
실제로 새 인스턴스를 작성하지 않는 것을 알기 위해 문서를 읽어야합니다 .
싱글 톤을 수행하는 또 다른 방법이 있습니다 (기본적으로 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
, 최상위 게터 대신에.
또한 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
_Impl
Singelton._internal()
. singelton 클래스의 개발자는 클래스를 여러 번 설치할 수도 있다고 주장 할 수 있습니다. 물론 enum 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}
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
패턴.참고 : 싱글 톤을 사용하는 코드가 일관되도록 세 가지 옵션 중 하나만 구현해야합니다.
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));