
학습이란 나새끼의 두뇌에 새로운 로직들을 인코딩하는 과정이다.
이 과정에서 수많은 버그가 발생하는데,
그 버그들을 하나하나 찾아내서 디버깅하는 것이 학습 과정의 본질이다.
오늘은 JSON을 다루는 방법을 학습했는데,
뭔가 또 이해되지 않는 지점이 있었다.
왜지? 왜 어디서부터 이해가 안되지? 하고 또 몇 번이나 같은 코드를 반복해서 작성하다가,
: this () 형태의 생성자를 본 적이 없는 것 같은 느낌이.알고보니 이건 학습 범위 밖에 있던 것으로, 나는 배운 적이 없는 코드였다.
버그가 생긴 이유가 이것 때문만은 아니겠지만. 아무튼 업데이트 한다는 생각으로 repo에 올려놓기.
named constructor (이름이 붙은 생성자)
기본 생성자
class Pet {
String name;
Pet(this.name);
}이 클래스는 이렇게만 만들 수 있어요:
Pet pet = Pet("초코");named constructor 추가
class Pet {
String name;
Pet(this.name);
Pet.fromJson(Map<String, dynamic> json) {
name = json['name'];
}
}
이제 객체를 두 가지 방법으로 만들 수 있습니다.
Pet pet1 = Pet("초코");
Pet pet2 = Pet.fromJson(json);
👉
fromJson이 named constructor입니다.[4] 왜 이름을 붙이느냐?
생성자의 역할이 달라질 때 이름을 붙입니다.
Pet()→ 직접 값 넣어서 생성
Pet.fromJson()→ JSON에서 생성
Pet.empty()→ 기본값으로 생성
즉,
“이 객체가 어떤 경로로 만들어졌는지”를 코드에서 드러내기 위해
[5] 생성자 vs named constructor 차이
구분 | 기본 생성자 | named constructor |
이름 | 클래스 이름 그대로 | 클래스.이름 |
개수 | 보통 1개 | 여러 개 가능 |
용도 | 일반 생성 | 특정 목적 생성 |
생성자 위임이란
기본 생성자
class Pet {
String name;
int age;
Pet({
required this.name,
required this.age,
});
}이 생성자가 기준 생성자입니다.
❌ 위임 없이 named constructor 작성
Pet.fromJson(Map<String, dynamic> json) {
name = json['name'];
age = json['age'];
}문제점:
- 필드 초기화 로직이 여러 생성자에 분산
- 필드 초기화 로직: Pet 객체가 만들어질 때 name과 age에 어떤 값을 어떻게 넣을지에 대한 규칙
- 생성자가 늘어날수록 중복 + 실수 증가
- “회원”이라는 개념은 하나
- 가입 방법은 여러 개
- 타입은 하나
- 개념도 하나
- 인스턴스도 전부
Member - 가입 방법이 다르니까
- 들어오는 값도 다르고
- 검증 방식도 다를 수 있음
- 타입 동일 (
Member) - 클래스 동일
- 이후 사용 방식도 동일
- 실수 방지
- 의도 명확
- 잘못된 조합 차단
하나의 클래스에서 복수의 생성자를 쓸 수 있는가? ⇒ 가능
혼잣말
이것도 버그다. 수업에서 배운 적 없는데 막 나와버려 ㅅㅂ.
그럼 나는 이걸 내가 배웠는데 놓친 건가? 어디서부터 놓친 거지? 이 지랄 하면서 디버깅하다가 수업 중에 나온 적 없다는 걸 확인하고 안심하게 됨. Hㅏ…
사이트에 회원가입할 때,
1) 구글 로그인으로 가입한 사람
2) 카카오톡으로 가입한 사람
3) 네이버 로 가입한 사람
4) 이메일주소로 가입한 사람 등 가입하는 방법은 다양하겠지만,
"가입"한다는 클래스는 하나인 거잖아.
그러니까 클래스는 "가입"하는 것 하나지만
가입 객체를 만드는 입구(생성 경로)를 4개 제공해야 한다.
네 비유를 Dart 생성자로 정확히 대응시켜보면
네가 말한 상황
Dart로 옮기면
class Member {
String id;
String provider;
Member(this.id, this.provider);
Member.google(String googleId)
: this(googleId, "google");
Member.kakao(String kakaoId)
: this(kakaoId, "kakao");
Member.naver(String naverId)
: this(naverId, "naver");
Member.email(String email)
: this(email, "email");
}이 구조가 정확히 네가 말한 상황이야.
여기서 핵심 포인트 3가지
1️⃣ 클래스는 “회원” 하나
Member
👉 이건 네 말 그대로 완벽하게 맞음
2️⃣ 생성자는 “가입 경로(입구)” 여러 개
Member.google(...) Member.kakao(...) Member.naver(...) Member.email(...)
👉 입구는 여러 개가 필요
3️⃣ 결과물은 항상 같은 “회원 인스턴스”
Member a = Member.google("123");
Member b = Member.kakao("456");이 둘은:
👉 “어떻게 가입했는지”는 생성 시점에만 중요
네 이해를 한 문장으로 정리하면
“회원이라는 클래스는 하나지만, 회원이 되는 방법(생성 경로)이 여러 가지라서 그만큼 생성자를 제공한다.”
이 문장은 완전히 맞다.
딱 하나 더 중요한 보너스 개념
왜 이걸 굳이 생성자로 하느냐?
Member(provider: "google", id: "123");이렇게도 만들 수 있는데 굳이?
👉 이유는:
Member.google("123"); // 이게 훨씬 안전✅ 생성자 위임 사용
Pet.fromJson(Map<String, dynamic> json)
: this(
name: json['name'],
age: json['age'],
);
의미를 말로 풀면:
“fromJson으로 객체를 만들긴 하는데,실제 초기화는 기본 생성자 Pet(...)가 하게 하자”
즉,
fromJson은 값만 가공
- 초기화 책임은 하나의 생성자에 집중
[4] 문법 구조를 한 줄로 해석해보면
Pet.fromJson(...) : this(...)
:→ 초기화 리스트
this(...)→ 같은 클래스의 다른 생성자 호출
- 생성자 body
{}는 없거나 비어 있어야 함
👉 객체가 완전히 만들어지기 전에
👉 “이 생성자를 대신 실행해라”라고 지시하는 구조
Share article