2023-11-20
1. 정의
factory 생성자는 매번 새로운 인스턴스를 생성하여 리턴할 필요가 없는 경우에 사용할 수 있는 키워드이다. 즉 factory 키워드를 사용하면, 캐시 되어 있는 인스턴스나 해당 클래스의 하위타입을 리턴할 수 있다.
2. 예제
아래는 Dart 공식 문서에 있는 Logger예제이다.
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(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);
}
}
static final Map<String, Logger> _cache = <String, Logger>{};
logger 인스턴스를 이름에 기반하여 캐싱하는 정적 Map 코드
return _cache.putIfAbsent(name, () => Logger._internal(name));
해당 코드는 주어진 이름으로 이미 캐시된 인스턴스가 있다면 해당 인스턴스를 반환하고 그렇지 않으면 새로운 인스턴스를 생성하고 캐시에 추가한 후 반환한다.
factory Logger.fromJson(Map<String, Object> json)
JSON 맵에서 logger 클래스의 인스턴스를 생성하는 팩토리 생성자 맵에서 'name' 필드를 추출하고 이를 사용하여 새로운 인스턴스를 생성한다.
3. 추가 사항
Factory constructors have no access to this. (팩토리 생성자는 this 키워드를 사용할 수 없다.)
그러면 여기서 궁금한 점이 드는 부분이 있을 것이다. factory Logger.fromJson(Map<String, Object> json)를 사용해서 객체를 생성하면 매번 새로운 객체가 나오는 거아니야? 라고 생각 할 수 있지만 그것은 아니다. 아래의 테스트 코드를 확인하면, 같은 name을 사용한 logger == loggerJson1 == loggerJson2 는 같은 객체라고 나오지만 다른 이름을 사용한 loggerJson3만 다른 객체라고 나오는 것을 알 수 있다. 즉 동일한 정보를 가진 클래스 정보에 대해서는 이미 생성된 인스턴스를 리턴한다는 것을 알 수 있다.
void main() {
var logger = Logger('UI');
logger.log('Button clicked');
var logMap = {'name': 'UI'};
var loggerJson1 = Logger.fromJson(logMap);
var loggerJson2 = Logger.fromJson(logMap);
// 두 객체를 비교합니다.
if (logger == loggerJson1) {
print('logger와 loggerJson1은 동일한 객체입니다.');
} else {
print('logger와 loggerJson1은 다른 객체입니다.');
}
if (loggerJson2 == loggerJson1) {
print('loggerJson2와 loggerJson1은 동일한 객체입니다.');
} else {
print('loggerJson2와 loggerJson1은 다른 객체입니다.');
}
var logMap2 = {'name': 'UI2'};
var loggerJson3 = Logger.fromJson(logMap2);
if (loggerJson2 == loggerJson3) {
print('loggerJson2와 loggerJson3은 동일한 객체입니다.');
} else {
print('loggerJson2와 loggerJson3은 다른 객체입니다.');
}
}
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(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);
}
}
4. 참고 링크
https://dart.dev/language/constructors#factory-constructors