반응형
Jake Seo
제이크서 위키 블로그
Jake Seo
전체 방문자
오늘
어제
  • 분류 전체보기 (715)
    • 일상, 일기 (0)
    • 백준 문제풀이 (1)
    • 릿코드 문제풀이 (2)
    • 알고리즘 이론 (10)
      • 기본 이론 (2)
      • 배열과 문자열 (8)
    • 데이터베이스 (15)
      • Planet Scale (1)
      • MSSQL (9)
      • 디비 기본 개념 (1)
      • SQLite 직접 만들어보기 (4)
    • 보안 (7)
    • 설계 (1)
    • 네트워크 (17)
      • HTTP (9)
      • OSI Layers (5)
    • 회고 (31)
      • 연간 회고 (2)
      • 주간 회고 (29)
    • 인프라 (52)
      • 도커 (12)
      • AWS (9)
      • 용어 (21)
      • 웹 성능 (1)
      • 대규모 서비스를 지탱하는 기술 (9)
    • 깃 (7)
    • 빌드 도구 (7)
      • 메이븐 (6)
      • 그레이들 (0)
    • Java (135)
      • 이펙티브 자바 (73)
      • 자바 API (4)
      • 자바 잡지식 (30)
      • 자바 디자인 패턴 (21)
      • 톰캣 (Tomcat) (7)
    • 프레임워크 (64)
      • next.js (14)
      • 스프링 프레임워크 (28)
      • 토비의 스프링 (6)
      • 스프링 부트 (3)
      • JPA (Java Persistence API) (5)
      • Nest.js (8)
    • 프론트엔드 (48)
      • 다크모드 (1)
      • 노드 패키지 관리 매니저 (3)
      • CSS (19)
      • Web API (11)
      • tailwind-css (1)
      • React (5)
      • React 새 공식문서 요약 (1)
      • HTML (Markup Language) (5)
    • 자바스크립트 (108)
      • 모던 자바스크립트 (31)
      • 개념 (31)
      • 정규표현식 (5)
      • 코드 스니펫 (1)
      • 라이브러리 (6)
      • 인터뷰 (24)
      • 웹개발자를 위한 자바스크립트의 모든 것 (6)
      • 팁 (2)
    • Typescript (49)
    • 리눅스와 유닉스 (10)
    • Computer Science (1)
      • Compiler (1)
    • IDE (3)
      • VSCODE (1)
      • IntelliJ (2)
    • 세미나 & 컨퍼런스 (1)
    • 용어 (개발용어) (16)
      • 함수형 프로그래밍 용어들 (1)
    • ORM (2)
      • Prisma (2)
    • NODEJS (2)
    • cypress (1)
    • 리액트 네이티브 (React Native) (31)
    • 러스트 (Rust) (15)
    • 코틀린 (Kotlin) (4)
      • 자바에서 코틀린으로 (4)
    • 정규표현식 (3)
    • 구글 애널리틱스 (GA) (1)
    • SEO (2)
    • UML (2)
    • 맛탐험 (2)
    • 리팩토링 (1)
    • 서평 (2)
    • 소프트웨어 공학 (18)
      • 테스팅 (16)
      • 개발 프로세스 (1)
    • 교육학 (1)
    • 삶의 지혜, 통찰 (1)
    • Chat GPT (2)
    • 쉘스크립트 (1)
    • 컴파일 (2)
    • Dart (12)
    • 코드팩토리의 플러터 프로그래밍 (4)
    • 플러터 (17)
    • 안드로이드 스튜디오 (1)
    • 윈도우즈 (1)
    • 잡다한 백엔드 지식 (1)
    • 디자인 패턴 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 이펙티브 자바 item9
  • 외래키 제약조건
  • MSSQL
  • 느린 쿼리
  • 슬로우 쿼리
  • 자바스크립트
  • prerendering
  • next js app
  • serverless computing
  • 플라이웨이트패턴
  • 자바스크립트 인터뷰
  • 싱글톤 패턴
  • 서버리스 컴퓨팅
  • 팩터리 메서드 패턴
  • 빈 검증
  • Pre-rendering
  • 자바 디자인패턴
  • Next.js
  • 메이븐 라이프사이클
  • 싱글턴
  • 자료구조
  • item7
  • 자바스크립트 면접
  • 이펙티브자바
  • Javadoc 자바독 자바주석 주석 Comment
  • 작업기억공간
  • try-with-resources
  • item8
  • rust
  • 프로그래머의 뇌
  • pnpm
  • 알고리즘
  • 디자인패턴
  • 러스트
  • 메이븐 골
  • 도커공식문서
  • 토비의 스프링
  • 싱글톤
  • item9
  • 메이븐 페이즈
  • 추상 팩터리 패턴
  • bean Validation
  • 이펙티브 자바
  • 자바
  • 스프링 검증
  • Java
  • 객체복사
  • NEXT JS
  • 참조 해제
  • 자바 검증

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jake Seo

제이크서 위키 블로그

Dart

다트 (Dart) 언어의 생성자 (Constructors) 정리

2023. 10. 13. 21:41

생성자

  • 클래스와 같은 이름의 함수를 생성하면 생성자가 된다.
    • (선택적으로) 이름을 부여하면 명명된 생성자 (Named constructors) 를 만들 수 있다.
  • 클래스의 인스턴스를 생성하기 위한 일반 생성자를 generative constructor 라 한다.
class Point {
  double x = 0;
  double y = 0;

  Point(double x, double y) {
    // 사실 인스턴스 변수를 초기화하는 더 좋은 방법이 있다.
    this.x = x;
    this.y = y;
  }
}

Dart 에서 this 는 이름 충돌(name conflict)이 발생할 때만 사용하는 것이 좋다. 다트 스타일은 this 를 생략한다.

공식 매개변수 초기화하기 (initializing formal parameters)

  • 생성자의 인자를 인스턴스 변수에 할당하는 패턴은 매우 일반적이다.
  • 다트는 initializing formal parameter 를 통해 이를 쉽게 초기화하도록 도와준다.
  • null 이 될 수 없는 인스턴스 변수 (non-nullable instance variable) 혹은 final 인스턴스 변수에도 사용할 수 있다.
    • 위 두가지 경우는 반드시 초기화 되어야 하는 인스턴스 변수의 예이다.
class Point {
  final double x;
  final double y;

  // 생성자의 바디 부분이 동작하기 전에 x, y 인스턴스 변수가 할당(set)된다.
  Point(this.x, this.y);
}

기본 생성자

  • 아무 생성자도 정의하지 않았을 때 생성된다.
  • 상위 클래스에서 아무런 인자가 없는 생성자를 호출한다.

생성자는 상속되지 않는다

  • 하위 클래스는 상위 클래스의 생성자를 상속받지 않는다.
  • 아무런 생성자를 정의하지 않은 경우 기본 생성자만 가진다.

명명된 생성자 (Named constructors)

  • 더 명시적인 여러 개의 생성자를 가진 클래스를 만들 때 유용하다.
  • 생성자는 상속되지 않는 점을 다시 한번 상기하자. 이는 명명된 생성자도 마찬가지이다.

  • [[2.1 item1. 생성자 대신 정적 팩터리 메서드를 고려하라]]
  • 자바의 정적 팩터리 메서드를 언어 차원에서 지원해주는 느낌이다.

const double xOrigin = 0;
const double yOrigin = 0;

class Point {
  final double x;
  final double y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin()
      : x = xOrigin,
        y = yOrigin;
}

기본 생성자가 아닌 상위 클래스의 생성자 호출하기

  • 하위 클래스의 생성자는 기본적으로 슈퍼 클래스의 기본 생성자를 호출한다.
    • 생성자 바디의 시작 부분에서 호출된다.
  • 이니셜라이저 리스트도 사용 중이면, 슈퍼클래스가 호출되기 전에 실행된다.

실행 순서는 아래와 같다.

  1. 이니셜라이저 리스트
  2. 슈퍼 클래스의 인자 없는 생성자
  3. 메인 클래스의 인자 없는 생성자
  • 슈퍼 클래스에 이름 없고 인자 없는 생성자가 없다면, 슈퍼 클래스에서 생성자 하나를 선택해 직접 호출해야 한다.
  • 생성자 바디 바로 전에 있는 : 이후에 슈퍼 클래스의 생성자를 명시해줘야 한다.
class Person {
  String? firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person 클래스는 기본 생성자가 없기 때문에 `:` 이후에 어떤 생성자를 사용할지 명시해야 한다.
  Employee.fromJson(super.data) : super.fromJson() {
    print('in Employee');
  }
}

void main() {
  var employee = Employee.fromJson({});
  print(employee);
}
  • 슈퍼클래스 생성자에 대한 인수는 생성자를 호출하기 전에 평가되기 때문에 인수는 함수 호출 같은 표현식이 될 수 있다.
class Employee extends Person {
  Employee() : super.fromJson(fetchDefaultData());
}

슈퍼 클래스 생성자의 인자는 this 에 접근할 수 없다. static methods 는 호출할 수 있어도 인스턴스 메서드를 호출할 수는 없다. (아직 해당 인스턴스가 만들어지기 전이기 때문일 것 같다.)

이니셜라이저 리스트

  • 생성자 바디가 실행되기 전에 인스턴스 변수를 초기화할 수 있다.
  • 이니셜라이저는 쉼표로 구분한다.
  • final 로 된 필드를 설정하는데 매우 유용하다.
// 이니셜라이저 리스트는 생성자 바디가 실행되기 전에 인스턴스 변수 값을 설정한다.
Point.fromJson(Map<String, double> json)
    : x = json['x']!,
      y = json['y']! {
  print('In Point.fromJson(): ($x, $y)');
}

이니셜라이저의 우측에서는 this 에 접근할 수 없다.

import 'dart:math';

class Point {
  final double x;
  final double y;
  final double distanceFromOrigin;

  Point(double x, double y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

void main() {
  var p = Point(2, 3);
  print(p.distanceFromOrigin);
}
  • 개발 시 이니셜라이저 리스트에 assert 를 통해 값을 검증할 수 있다.
Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}

Super parameters

  • 생성자의 슈퍼 호출에 각 매개변수를 직접 전달하지 않으려면 슈퍼 이니셜라이저 매개변수를 사용하여 매개변수를 지정된 혹은 기본 슈퍼클래스 생성자로 전달할 수 있다.
  • 이 기능은 리디렉션 생성자와 함께 사용할 수 없다.
  • 슈퍼 이니셜라이저 매개변수는 formal parameters 를 초기화하는 것과 문법적으로 의미적으로 유사합니다.
class Vector2d {
  final double x;
  final double y;

  Vector2d(this.x, this.y);
}

class Vector3d extends Vector2d {
  final double z;

  // x, y 를 다음과 같이 슈퍼 생성자로 전달한다.
  // Vector3d(final double x, final double y, this.z) : super(x, y);
  Vector3d(super.x, super.y, this.z);
}
  • 상위 생성자 호출에 이미 위치가 있는 인수가 있다면, 슈퍼 이니셜라이저 매개변수 (super-initializer parameters) 는 위치가 있을 수 없다.
    • [[001.다트-언어-마스터하기#순서가 고정된 매개변수와 이름이 있는 매개변수]]
  • 하지만 항상 이름을 지정할 수 있다.
class Vector2d {
  // ...

  Vector2d.named({required this.x, required this.y});
}

class Vector3d extends Vector2d {
  // ...

  // Forward the y parameter to the named super constructor like:
  // Vector3d.yzPlane({required double y, required this.z})
  //       : super.named(x: 0, y: y);
  Vector3d.yzPlane({required super.y, required this.z}) : super.named(x: 0);
}

생성자 리다이렉팅하기

  • 때때로 생성자의 목적은 같은 클래스의 다른 생성자로 리다이렉팅하는 것이다.
  • 리다이렉팅 하는 생성자의 바디는 비어있고 : 뒤에 생성자 호출이 표현된다.
class Point {
  double x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(double x) : this(x, 0);
}

상수 생성자 (Constant constructors)

  • 클래스가 생성한 오브젝트가 변하지 않는다면, 오브젝트를 컴파일 타임 상수로 만들 수 있다.
  • const 생성자를 정의하고 모든 인스턴스 변수가 final 인지 확인해야 한다.
  • 상수 생성자가 항상 상수만 생성하진 않으므로 유의해야 한다.
    • const 키워드가 중요하다. [[001.다트-클래스#상수 생성자]]
class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

팩토리 생성자 (Factory constructors)

  • 항상 새로운 인스턴스를 생성하지 않는 생성자를 구현할 때, factory 라는 키워드를 사용한다.
  • 캐시에서 인스턴스를 가져오거나 하위 타입의 인스턴스를 반환할 수도 있다.
  • 이니셜라이저 리스트에서 처리할 수 없는 로직을 사용하여 final 변수를 초기화할 때도 사용한다.
    • [[004.생성자(constructors)#이니셜라이저 리스트]]

final 변수의 늦은 초기화를 다루고 싶다면 use late final 을 '조심스럽게' 참고해보는 것도 좋다.

  • 아래는 Logger 를 캐시에서 꺼내오는 코드의 예제이다.
  • Logger.fromJson 팩토리는 final 변수를 JSON 오브젝트로부터 초기화한다.
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);
  }
}

factory 생성자는 this 에 접근할 수 없다.

  • factory 생성자를 다른 생성자처럼 호출할 수 있다.
var logger = Logger('UI');
logger.log('Button clicked');

var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);

레퍼런스

https://dart.dev/language/constructors

반응형
저작자표시 비영리 (새창열림)

'Dart' 카테고리의 다른 글

다트의 비동기 지원 (Asynchronous Support)  (0) 2023.10.22
다트 비동기 프로그래밍 (Future, Async, Await)  (0) 2023.10.22
다트(Dart) 언어의 클래스(Class) 정리  (0) 2023.10.12
다트(Dart) 언어의 클래스 제어자 (Class modifier) 정리  (0) 2023.10.12
다트(Dart) 언어의 확장 메서드 (Extension methods) 정리  (0) 2023.10.10
    'Dart' 카테고리의 다른 글
    • 다트의 비동기 지원 (Asynchronous Support)
    • 다트 비동기 프로그래밍 (Future, Async, Await)
    • 다트(Dart) 언어의 클래스(Class) 정리
    • 다트(Dart) 언어의 클래스 제어자 (Class modifier) 정리
    Jake Seo
    Jake Seo
    ✔ 잘 보셨다면 광고 한번 클릭해주시면 큰 힘이 됩니다. ✔ 댓글로 틀린 부분을 지적해주시면 기분 나빠하지 않고 수정합니다. ✔ 많은 퇴고를 거친 글이 좋은 글이 된다고 생각합니다. ✔ 간결하고 명료하게 사람들을 이해 시키는 것을 목표로 합니다.

    티스토리툴바