Overview
-
Dart에서 JSON을 parsing하는 class를 만들 때
fromJson
이라는 factory named constructor를 만들곤 한다.class Person { final String name; final int age; Person({required this.name, required this.age}); // ✅ factory Person.fromJson(Map<String, dynamic> json) => Person(name: json["name"], age: json["age"]); }
-
그런데,
fromJson
constructor는 factory가 아니어도 아무 문제가 없다.class Person { final String name; final int age; Person({required this.name, required this.age}); // ✅ Person.fromJson1(Map<String, dynamic> json) : name = json["name"], age = json["age"]; }
-
Dart 문서의 예시에서도
fromJson
을 factory constructor로 만들고 있다.class Logger { // ... factory Logger(String name) { return _cache.putIfAbsent(name, () => Logger._internal(name)); } // Logger.fromJson factory constructor initializes a final variable from a JSON object. factory Logger.fromJson(Map<String, Object> json) { return Logger(json['name'].toString()); } // ... }
-
왜
fromJson
constructor는 factory로 만들라고 하는 것일까?
Factory constructor
- Dart 문서에서 factory constructor는 아래의 경우에 해당되면 사용하라고 설명하고 있다.
- Constructor가 subtype instance를 생성하거나, cache 등에서 이미 존재하는 instance를 가져와서 반환하는 경우
- Argument 검사 또는 initializer list에서 처리되지 않은 작업 등 instance 생성 과정에서 선행되어야 하는 중요한 작업을 수행해야 하는 경우
- 함께 소개된 예시 코드에서
Logger
constructor는 cache에서 객체를 가져와서 반환하므로 factory constructor를 사용하면 좋다. - 하지만,
Logger.fromJson
은 json object로부터name
data를 가져와서Logger
instance를 생성하고 있다. Json을 parsing하는 과정에서 선행되는 작업도 없고, json data를 사용해서 ‘항상’ 새 instance를 만들어서 반환하는데 왜 factory constructor로 만드는 것일까?
Defensive design
- Stack overflow에서 관련된 질문과 답변을 찾을 수 있었다.
- Factory constructor를 사용하는 것은 기술적으로 특별한 이유가 없더라도 defensive design을 위한 것이라고 한다.
- 일반적인 generative constructor를 만들면 subclass에서 forwarding이 가능해 진다.
- 이 constructor에 validation code를 추가하는 등의 변경이 필요하면 factory constructor로 변경해야 하는데, 이 class를 상속받는 subclass들 중 constructor를 forwarding 하고 있던 class에서 예상하지 못한 error가 발생할 가능성이 생긴다.
- 따라서,
fromJson
외에도 constructor는 먼저 factory로 만들고 필요할 때만 public generative constructor를 만드는게 안전하다고 한다.
Conclusion
- Stack overflow의 답변에 따르면, factory constructor를 사용하는 이유는 subclass에서 의도하지 않은 forwarding에 의한 error 가능성을 제거하는 목적이다.
- 하지만, 이것보다는 json 객체를 parsing하는 constructor의 역할 때문인 것 같다.
- 간단한 json 객체는 특별히 다른 logic이 필요없어 보이지만, 일반적으로 json 객체를 parsing할 때는 실패할 가능성이 존재하므로 이와 관련된 방어 코드 등의 logic이 필요할 수 있다.
- 따라서, json 객체로부터 instance를 생성하는 constructor는 factory constructor를 사용해야 하는 두 번째 이유에 해당한다고 생각한다.
- 이 질문에 대한 답은 정해진 것이 없으므로,
fromJson
은 일반적인 구현 패턴을 따라 factory constructor로 만드는게 좋을 것 같다.