what is factory?
flutter에서 모델 클래스를 만들 때 아래 같은 코드가 자주 사용된다.
그런데 factory라는 것을 dart에서 처음 봤다. factory 키워드는 무엇이고 어떤 역할을 할까?
class Book {
final String title;
final String description;
Book({this.title, this.description});
factory Book.fromJson(Map<String, dynamic> json) {
return Book(
title: json['title'],
description: json['description'],
);
}
}
singleton pattern
Use the factory keyword when implementing a constructor that doesn’t always create a new instance of its class
dart 도큐먼트에 나오는 factory에 대한 설명이다. 새로운 인스턴스를 생성하지 않는 생성자를 구현할 때 factory 키워드를 사용하라고 한다.
factory는 새로운 인스턴스를 생성하고 싶지 않을 때 사용하는 생성자이다. 이와 같은 개념은 새로운 게 아니다. 소프트웨어 디자인 패턴 중 '싱글톤 패턴'을 따른 것이다.
🧚♀️싱글톤 패턴(singleton-pattern): 소프트웨어 디자인 패턴에서 싱글톤 패턴을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글톤 패턴이라고 한다.
factory 특징
매번 인스턴스를 새로 생성하여 비용이 많이 드는 (generative) constructor와 달리 factory에는 몇 가지 특징이 있다.
- 기존에 이미 생성된 인스턴스가 있다면 return 하여 재사용한다.
- 하나의 클래스에서 하나의 인스턴스만 생성한다(싱글톤 패턴).
- 서브 클래스 인스턴스를 리턴할 때 사용할 수 있다.
- Factory constructors 에서는 this 에 접근할 수 없다.
contructor를 사용한 클래스는 항상 새로운 인스턴스를 리턴한다.
class Book {
final String title;
final String description;
Book({this.title, this.description});
}
final book = Book(...); // 항상 새로운 Book 인스턴스를 생성한다.
factory는 '클래스와 같은 타입의 인스턴스' 또는 '메서드를 구현하는 인스턴스'를 리턴하기만 하면 된다. 이렇게 생성된 인스턴스는 기존에 생성된 인스턴스가 아니라면 새롭게 생성되고, 기존 인스턴스가 있다면 기존 것을 리턴한다.
아래 코드에서 Logger()가 호출될 때마다 Logger factory 생성자가 호출된다. 만약 Logger('flutter')를 처음 호출하면 _*cache에 없으니 Logger.*internal('flutter') 으로 인스턴스를 새로 생성하여 반환한다(1번). 새로 생성된 인스턴스는 _cache에 저장된다(2번). 한 번 더 호출하면 _cache에 인스턴스가 있으니 기존 인스턴스를 반환한다.
factory는 공장이라는 이름 때문에 인스턴스를 새로 생성하는 공장이라고 착각하기 쉽다. 사실은 warehouse, 창고의 의미와 더 가깝다.
class Logger {
final String name;
bool mute = false;
static final Map<String, Logger> _cache =
<String, Logger>{};
// 1번
factory Logger(String name) {
return _cache.putIfAbsent( // 2번
name, () => Logger._internal(name));
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
factory는 서브클래스의 인스턴스를 반환할 때도 사용할 수 있다고 했다. 아래는 Book 클래스의 서브클래스인 ComicBook의 인스턴스를 반환하는 코드이다. 추가로 contructor와 factory는 아래처럼 named 생성자를 사용할 수 있다.
class Book {
// named generative
Book.comic(String title) : this(title, "Champ");
// named factory
factory Book.comic(String title) {
return ComicBook(title);
}
}
class ComicBook extends Book {
ComicBook(String title) : super(title, "Champ");
}
references
'개발 이야기 > flutter' 카테고리의 다른 글
[dart] 타입 캐스팅, 옵셔널 체이닝 | type casting + optional chaining (0) | 2021.02.26 |
---|---|
[flutter] graphql code generator | artemis 사용 방법과 장단점 (2) | 2021.02.26 |
[flutter] 불필요한 rerendering을 피하는 방법 | AutomaticKeepAliveClientMixin (1) | 2021.02.26 |
[Flutter] 자식 위젯에서 부모 위젯 state 참조하는 방법 | findAncestorStateOfType (0) | 2021.02.26 |