[Flutter] Dart에서 Singleton pattern사용하기

Seong-Am Kim
5 min readFeb 12, 2022

--

Photo by Martin Shreder on Unsplash

Singleton pattern은 객체지향 프로그래밍에 있어서 아주 중요한 개념이다.

오늘은 Dart에서 Singleton 을 사용하는 방법에 대한 코드를 먼저 살펴보고 이를 하나 하나 뜯어보면서 분석해보고자 한다.

해당 글은 아래와 같은 순서로 진행된다.

  1. 싱글톤(Singleton) 패턴에 대한 개념
  2. Dart에서 싱클톤 패턴 만드는 방법

싱글톤(Singleton) 패턴에 대한 개념

싱글톤(Singleton) 패턴의 정의는 매우 간단하다.

객체의 인스턴스가 오직 하나만 생성되는 것, 즉 여러개의 생성자를 호출 하더라도 실제로 생성되는 인스턴스는 하나이다.

해당 부분을 코드로 살펴보자면 아래와 같다.

main() {
Singleton s1 = Singleton();
Singleton s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}

싱글톤을 이용하게 되면 때에 따라 메모리 사용 측면에 있어서 효율성을 가져갈 수 있고 데이터간 공유가 쉽기 때문에 이를 위해 주로 이용된다.

하지만 위의 이유로 동시성 프로그래밍에 있어서 같은 데이터를 동시에 접근하게 되면 문제가 발생할 수 있으므로 설계시 이 점에 유의 해야 한다.

Dart에서 싱클톤 패턴 만드는 방법

우선 코드부터 살펴보자.

중요한 키워드 부터 정리하고 넘어가보자.

static

변수 또는 메서드가 인스턴스에 귀속되는 것이 아닌 클래스에 귀속되는 것

factory

factory의 경우 Dart에서 제공해주는 다소 특이한 키워드인데, 결국 생성자이다.

하지만 기존의 생성자와는 달리 반환값에 있어서 새로운 인스턴스의 생성이 가능하므로 좀 더 유연한 프로그래밍을 가능하게 한다.

위의 말은 같은 데이터 타입을 가지면 해당 인스턴스를 모두 return 할수 있다는 이야기이다.

예를 들면 factory가 선언된 클래스를 상속받은 자식 클래스의 인스턴스 또한 return이 가능하다.

...
// named generative
// delegates to the default generative constructor
Person.greek(String name) : this(name, "Greece");

// named factory
factory Person.greek(String name) {
return Greek(name);
}
}

class Greek extends Person {
Greek(String name) : super(name, "Greece");
}

해당 키워드를 이해하고 다시 한번 코드를 살펴보자.

여기서 아직 이해가 안가는 부분이 아래 두라인이라고 생각한다.

Singleton._privateConstructor();
static final Singleton _instance = Singleton._privateConstructor();

흔히 프로그래밍에서 이름(); 는 호출만을 의미하는 경우가 많기 때문에 혼동이 발생하게 되는 것이다.

결론부터 말하자면 Singleton._privateConstructor(); 이것은 호출이 아니라 생성자를 만드는 선언부이다.

빈생성자를 만드는 선언으로 이를 풀어서 표현하면 아래와 같다.

SingletonOne._privateConstructor() {

}

이를 약식으로 적은것이 Singleton._privateConstructor(); 이다.

참고로 클래스이름 뒤에 생성자 이름은 무엇이 와도 상관없다. 예를 들어 Singleton.someConstructor(); 이렇게 아무 이름이나 적어줘도 상관 없다.

그렇다면 왜 이렇게 굳이 빈 생성자를 생성하는 것일까?

Dart에선 생성자가 없을경우 자동으로 Public한 생성자를 만들어 버린다. 이를 막기위해 Private한 생성자를 만들어줘서 자동으로 만들어주는 생성자가 생성 되지 않도록 방지하는 것이다.

(Dart에서 언더바(‘_’) 를 붙이게 되면 Private을 의미한다.)

다음으로 static final Singleton _instance = Singleton._privateConstructor(); 에 대해 살펴보자.

이의 경우 앞의 경우와 달리 생성자를 호출하는 것으로 호출한 결과의 인스턴스를 _instance 변수에 할당한 것이다.

마지막으로 이를 다시 정리 해보자면 아래와 같다.

class Singleton {
// Private한 생성자 생성
Singleton._privateConstructor();
// 생성자를 호출하고 반환된 Singleton 인스턴스를 _instance 변수에 할당 static final Singleton _instance = Singleton._privateConstructor();// Singleton() 호출시에 _instance 변수를 반환
factory Singleton() {
return _instance;
}
}

결과적으로 Singleton(); 을 호출 할때 마다 factory에서 같은 인스턴스가 반환되므로 싱글톤 패턴이 만들어 진다.

--

--