일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스택 큐 차이
- 객체
- 스택 자바 코드
- 멤버변수
- android retrofit login
- 안드로이드 레트로핏 사용법
- 안드로이드 os 구조
- rxjava disposable
- 서비스 쓰레드 차이
- ANR이란
- rxjava hot observable
- 큐 자바 코드
- Rxjava Observable
- 안드로이드 라이선스
- 자바 다형성
- rxjava cold observable
- 안드로이드 유닛 테스트 예시
- jvm이란
- 안드로이드 유닛 테스트
- jvm 작동 원리
- 2022 플러터 설치
- 안드로이드 레트로핏 crud
- 안드로이드 유닛테스트란
- android ar 개발
- 안드로이드 라이선스 종류
- 서비스 vs 쓰레드
- 2022 플러터 안드로이드 스튜디오
- 클래스
- ar vr 차이
- 플러터 설치 2022
- Today
- Total
나만을 위한 블로그
[Dart] 생성자(constructor) 알아보기 본문
이 포스팅에선 Dart에서 생성자를 어떻게 사용하는지 확인한다. 포스팅에서 사용할 Dart 버전은 3.4.4임을 참고한다.
아래는 플러터 공식문서 중 생성자의 공식문서다.
https://dart.dev/language/constructors
생성자는 클래스의 인스턴스를 만드는 특수 함수다. 기본 생성자를 제외하고 이런 함수는 클래스와 같은 이름을 쓴다
< 생성자 종류 >
- Generative constructors : 새 인스턴스를 만들고 인스턴스를 초기화
- Default constructors : 생성자가 지정되지 않은 경우 새 인스턴스를 만들 때 사용. 인수를 받지 않고 이름이 지정되지 않음
- Named constructors : 생성자의 목적을 명확히 하거나 같은 클래스에 대해 여러 생성자를 만들 수 있게 한다
- Constant constructors : 인스턴스를 컴파일 타임 상수로 생성
- Factory constructors : 하위 타입의 새 인스턴스를 만들거나 캐시에서 기존 인스턴스를 리턴함
- Redirecting constructors : 같은 클래스의 다른 생성자로 호출을 전달
아래는 각 생성자 별 설명이다.
Generative constructors
클래스를 인스턴스화할 때 사용한다.
class Point {
// 변수, 값의 Initializer 목록
double x = 2.0;
double y = 2.0;
// 공식 파라미터를 초기화하는 Generative constructor
Point(this.x, this.y);
}
x, y의 2가지 값을 받아서 Point 클래스의 인스턴스를 생성한다. 둘 다 2.0으로 초기화되어 있어서 메인 함수에서 사용할 땐 이 값을 사용하게 된다.
하지만 이 상태로 사용하려 할 경우 컴파일 에러가 발생하고 실행도 되지 않는다.
이 에러는 생성자 매개변수에 아무 소수나 넣어주면 해결된다. 값 출력도 정상적으로 이뤄진다.
void main() {
Point p = Point(2.0, 2.0);
print(p.x);
print(p.y);
}
class Point {
double x = 2.0;
double y = 2.0;
Point(this.x, this.y);
}
// >> 2.0
// >> 2.0
Point 클래스 안에서 x, y를 각각 2.0으로 초기화한 다음 메인 함수에서 사용하려고 한 건데 왜 안되는 건가?
값을 받는 생성자만 존재하기 때문이다. 위 코드는 아래와 같이 수정하면 작동한다.
void main() {
Point p = Point();
print(p.x);
print(p.y);
}
class Point {
double x = 2.0;
double y = 2.0;
Point();
}
또는 아래처럼 작성할 수도 있다.
void main() {
Point p = Point();
print(p.x);
print(p.y);
}
class Point {
double x = 2.0;
double y = 2.0;
Point({this.x = 2.0, this.y = 2.0});
}
2번째 코드는 값을 받아도 되고 안 받아도 된다. x, y에 다른 숫자를 넣어서 초기화하고 싶은 경우 사용할 수 있다.
Default constructors
기본 생성자라는 뜻인데 만약 클래스에 생성자를 만들어두지 않으면 dart가 이 기본 생성자를 사용한다.
참고로 클래스에 없던 생성자가 코드 에디터에 갑자기 생기는 건 아니다. 클래스 인스턴스를 만들 때 dart 컴파일러가 내부적으로 호출하는 것이라 실제론 볼 수 없다.
이 기본 생성자가 있기 때문에 만약 생성자를 정의하지 않았더라도 Point()를 써서 Point 클래스의 인스턴스를 만들어 사용할 수 있는 것이다.
기본 생성자는 생성자 매개변수, 이름이 없는 Generative constructor다.
Named constructors
명명된 생성자라고 번역되는데 이걸 써서 클래스에 여러 생성자를 구현하거나 명확성을 높일 수 있다.
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
// 생성자 본문이 실행되기 전에 x, y 변수 초기화
Point(this.x, this.y);
// Named constructor
Point.namedConstructor()
: x = xOrigin,
y = yOrigin;
}
Point를 상속하는 서브클래스는 Named constructor를 상속하지 않는다.
슈퍼클래스에 정의된 Named constructor가 있는 서브클래스를 만들려면 서브클래스에서 해당 생성자를 구현해야 한다.
예를 들면 아래와 같다.
void main() {
// 기본 생성자 사용
ColorPoint cp = ColorPoint(4.0, 5.0, "빨강");
print(cp);
// Named constructor 사용
ColorPoint cpNamed = ColorPoint.namedConstructor("파랑");
print(cpNamed);
}
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
// 생성자 본문이 실행되기 전에 x, y 변수 초기화
Point(this.x, this.y);
// Named constructor
Point.namedConstructor()
: x = xOrigin,
y = yOrigin;
}
class ColorPoint extends Point {
final String color;
// 기본 생성자
ColorPoint(double x, double y, this.color) : super(x, y);
// Named constructor를 서브 클래스에서 구현
ColorPoint.namedConstructor(this.color) : super.namedConstructor();
@override
String toString() => "ColorPoint(x : $x, y : $y, color : $color)";
}
Constant constructors
클래스가 불변 객체를 생성한다면 이런 객체를 컴파일 타임 상수로 만들라고 공식문서에 써 있다.
객체를 컴파일 타임 상수로 만들려면 모든 인스턴스 변수를 final 변수로 설정한 생성자를 정의해야 한다.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
그러나 상수 생성자라 해서 항상 상수를 만드는 건 아니다. 상수가 아닌 컨텍스트에서 호출될 수도 있다.
이 클래스를 사용하려면 아래와 같이 한다.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
var p = const ImmutablePoint(2, 2);
print(p.x);
print(p.y);
}
// >> 2.0
// >> 2.0
2개의 컴파일 타임 상수를 만들어 비교하면 두 상수가 일치한다.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
bool isAbEquals = identical(a, b);
print(isAbEquals); // true
assert(identical(a, b)); // 프로그램 정상 종료됨. 만약 둘이 다르다면 에러가 발생한다
}
Redirecting constructors
생성자는 같은 클래스의 다른 생성자로 리디렉션될 수 있다. 이 때 리디렉션 생성자를 사용한다.
이 생성자엔 빈 본문이 있고 콜론 뒤에 이름 대신 this를 사용한다.
class Point {
double x, y;
// Point 클래스의 주 생성자
Point(this.x, this.y);
// 주 생성자에 위임
Point.alongXAxis(double x) : this(x, 0);
}
재사용성, 가독성, 코드 안전성을 향상시킬 수 있는 생성자라고 하는데 아직 많이 사용해보지 않아서 잘 모르겠다.
Factory constructors
생성자를 구현하는 중 아래 2가지 중 하나의 경우에 해당하면 factory 키워드를 사용하라고 권장한다.
- 생성자가 항상 그 클래스의 새 인스턴스를 만드는 건 아니다. 팩토리 생성자는 null을 리턴할 순 없지만 아래를 리턴할 수 있다
- 캐시에서 기존 인스턴스를 가져옴
- 하위 타입의 새 인스턴스
- 인스턴스 생성 전에 사소하지 않은 작업(매개변수 확인, 이니셜라이저 리스트에서 처리할 수 없는 다른 처리 작업 등)을 수행해야 하는 경우
아래는 예시다.
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);
}
}
Logger는 캐시에서 객체를 리턴하는 팩토리 생성자고, Logger.fromJson은 JSON 객체에서 final 변수를 초기화하는 팩토리 생성자다.
그리고 팩토리 생성자는 this에 접근할 수 없다. 아래 블로그에서 그 이유를 설명하는데 참고용으로 가져왔다.
https://medium.com/@chetan.akarte/in-dart-what-is-factory-constructors-658436155d06
this 접근 불가 : 팩토리 생성자는 인스턴스 변수나 메서드에 직접 접근할 수 없다. 인스턴스별 데이터에 의존하지 않는 복잡한 인스턴스화 로직에 주로 사용한다
참고한 사이트)
https://dart.dev/language/classes#using-constructors
https://medium.com/nerd-for-tech/named-constructor-vs-factory-constructor-in-dart-ba28250b2747
'Flutter' 카테고리의 다른 글
[Flutter] Future, async / await를 통한 비동기 처리 방법 (0) | 2024.07.24 |
---|---|
[Dart] final vs const (0) | 2024.07.22 |
[Flutter] Scaffold란? (0) | 2024.07.17 |
[Flutter] Android sdk Android api 29 platform is not found on the disk 경고 해결 (0) | 2024.04.13 |
[Dart] Record란? (0) | 2024.04.11 |