Dart 기본 문법 05

GreenBean·2023년 4월 4일
0
post-thumbnail

Dart

Dart 공식문서
다트 ( Dart ) 생성자 1
다트 ( Dart ) 생성자 2

Dart 의 생성자

  • 클래스에는 생성자가 따름
    • 생성자는 이름처럼 클래스가 인스턴스화 될 때, 즉 객체가 생성될 때 호출
  • 생성자
    • 기본 생성자 ( Default Constructor )
    • 이름 있는 생성자 ( Named Constructor )
    • 초기화 리스트 ( Initializer List )
    • 리다이렉팅 생성자 ( Redirecting Constructor )
    • 상수 생성자 ( Constant Constructor )
    • 팩토리 생성자 ( Factory Constructor )

기본 생성자

# Default constructor

// class 클래스명 {
//   클래스명() {
//   }
// }

class Person {
  Person() {
  }
}
  • 클래스를 구현할 때 생성자를 선언하지 않으면 (=생략하면) 기본 생성자가 자동으로 제공
    • 기본 생성자는 클래스명과 동일하면서 인자가 없음
    • 또한 기본 생성자는 부모 클래스의 인수가 없는 생성자(=기본 생성자)를 호출함
# 예시

class Person {
  Person() {
    print("This is Person constructor!");
  }
}

class Student extends Person {
}

main() {
  var student = Student();
}

------------------------------------------------------------------------------------------

# 결과

This is Person constructor!
  • 상속에 대해서 다루기 전이라 간단히 설명하면 부모 클래스는 자식 클래스에게 멤버를 물려주는(=상속하는) 관계
    • 위의 코드에서 Person 클래스가 부모 클래스이고 Student 클래스가 자식 클래스
    • extends 키워드가 어떤 클래스로부터 상속받을지 지정하는 역할을 함
  • 위의 코드에서 보면 Student 클래스에는 생성자가 없음
    • 따라서 자동으로 기본 생성자가 제공됨
    • 기본 생성자는 부모 클래스의 기본 생성자를 호출
    • 실행 결과를 보면 부모 클래스인 Person 클래스의 기본 생성자가 호출되어 "This is Person constructor!" 가 호출되는 것을 확인 가능
  • 동작 방식을 도식화하면 다음과 같음
    • Student 클래스의 기본 생성자가 호출되고 거기서 부모 클래스의 기본 생성자를 호출한 것을 확인하고 싶다면 Student 클래스에 기본 생성자를 생성하면 됨

# 예시

class Person {
  Person() {
    print("This is Person constructor!");
  }
}

class Student extends Person {
  Student() {
    print("This is Student constructor!");
  }
}

main() {
  var student = Student();
}

------------------------------------------------------------------------------------------

# 결과

This is Person constructor!
This is Student constructor!
  • 위 코드의 실행 결과를 보면 부모 클래스 Person 의 기본 생성자가 호출된 후 자식 클래스 Student 의 기본 생성자가 호출된 것을 알 수 있음

Tip! 참고

  • 기본 생성자는 상속되지 않음
    • 자식 클래스는 부모 클래스의 생성자를 상속받지 않음
    • 앞서 말한 것처럼 자식 클래스에서 아무 생성자도 선언하지 않으면 기본 생성자만 가짐

이름 있는 생성자

# Named Constructor

// class 클래스명 {
//  클래스명.생성자명()
//  }
// }

class Person {
  Person.init() {
  }
}
  • 이름 있는 생성자는 말 그대로 생성자에 이름을 부여한 형태
    • 한 클래스 내에 많은 생성자를 생성하거나 생성자를 명확히 하기 위해서 사용할 수 있음
# 예시

class Person {
  Person() {
    print("This is Person Constructor!");
  }
  
  Person.init() {
    print("This is Person.init Constructor!");
  }
}

class Student extends Person {
  Student() {
    print("This is Student Constructor!");
  }
}

main() {
  var person = Person();
  var init = Person.init();
}

------------------------------------------------------------------------------------------

# 결과

This is Person Constructor!
This is Person.init Constructor!
  • 사용 방법은 객체 생성 시 이름 있는 생성자로 생성하면 됨
    • 위 코드를 보면 Person.init() 라는 생성자를 선언하였고 init 객체가 Person.init() 생성자를 통해 생성되었음

Tip! 참고

  • 이름 없는 생성자는 단 하나만 가질 수 있음
    • 또한 이름 있는 생성자를 선언하면 기본 생성자는 생략할 수 없음

초기화 리스트

# Initializer List

// 생성자 : 초기화 리스트 {
// }

Person() : name = "Kim" {
}
  • 초기화 리스트를 사용하면 생성자의 구현부가 실현되기 전에 인스턴스 변수를 초기화할 수 있음
    • 초기화 리스트는 생성자 옆에 : ( 콜론 ) 으로 선언할 수 있음
# 예시

class Person {
  String name;
  
  Person() : name = "Kim" {
    print("This is Person($name) Constructor!");
  }
}

main() {
  var person = Person();
}

------------------------------------------------------------------------------------------

# 결과

This is Person(Kim) Constructor!
  • 위 코드를 보면 Person 클래스에서 name 은 초기화된 적이 없음
    • 하지만 Person 객체를 만들면서 생성자 호출 시 초기화 리스트에서 Kim 으로 초기화
    • 생성자의 구현부에 진입 전 name 이 초기화되어서 출력할 때 Kim 이 출력됨

리다이렉팅 생성자

  • 초기화 리스트를 약간 응용하여 단순히 리다이렉팅을 위한 생성자를 만들 수 있음
    • 이러한 생성자는 본체가 비어있고 메인 생성자에게 위임 ( delegate ) 하는 역할을 함
# 예시

class Person {
  String name;
  int age;
  
  Person(this.name, this.age) {
    print("This is Person($name, $age) Constructor!");
  }
  
  Person.initName(String name) : this(name, 20);
}

main() {
  var person = Person.initName("Kim");
}

------------------------------------------------------------------------------------------

# 결과

This is Person(Kim, 20) Constructor!
  • 위 코드를 보면 이름 있는 생성자인 Person.initName(String name) 은 본체가 없고 초기화 리스트에 this(name, 20) 이라고 되어 있음
  • this 는 현재 인스턴스를 가리키는데 여기서 this(name, 20) 는 현재 인스턴스의 생성자인 Person(this.name, this.age) 이 됨
    • 따라서 Person.initName("Kim") 호출 시 Person(this.name, this.age) 의 인자로 Person.initName("Kim") 에서 받은 Kim 과 20 이 할당됨
      • Person() 의 인자에서 쓰인 this.name 은 현재 인스턴스의 name 을 의미

상수 생성자

  • 상수 생성자는 말 그대로 생성자를 상수처럼 만들어 줌
    • 이 말은 해당 클래스가 상수처럼 변하지 않는 객체를 생성한다는 것
    • 상수 생성자를 만들기 위해서는 인스턴스 변수가 모두 final 이어야 함
    • 또한 생성자는 const 키워드가 붙어야 함
# 예시

class Person {
  final String name;
  final num age;
  
  const Person(this.name, this.age);
}

main() {
  Person person1 = const Person("Kim", 20);
  Person person2 = const Person("Kim", 20);
  Person person3 = new Person("Kim", 20);
  Person person4 = new Person("Kim", 20);
  
  print(identical(person1, person2));
  print(identical(person2, person3));
  print(identical(person3, person4));
}

------------------------------------------------------------------------------------------

# 결과

true
false
false
  • 위 코드를 보면 Person 클래스 내에 인스턴스 변수에 final 키워드가 선언되어 있음
    • 또한 Person() 생성자는 const 키워드가 붙어있으
    • 상수 생성자를 만들기 위한 조건을 모두 갖춘 것
  • print() 에서 사용된 identical() 은 같은 인스턴스인지 비교해줌
    • person1 과 person2 는 상수 생성자를 참조하고 있음
    • 따라서 동일한 인스턴스를 참조하고 있기 때문에 true 가 됨
    • 그러나 person3 과 person4 는 각각 새로운 인스턴스를 생성했기 때문에 동일한 인스턴스를 가지지 않음
  • 그림으로 표현하면 아래와 같음

팩토리 생성자

  • 팩토리 생성자는 팩토리 패턴을 사용하기 편리
    • 팩토리 패턴을 사용하면 해당 클래스의 인스턴스를 매번 생성하지 않아도 됨
    • 보통 자식 클래스의 인스턴스를 리턴 받음
# 예시

class Person {
  Person.init();
  
  factory Person(String type) {
    switch (type) {
      case "Student":
        return Student();
      case "Employee":
        return Employee();
    }
  }
  
  String getType() {
    return "Person";
  }
}

class Student extends Person {
  Student() : super.init();
  
  
  String getType() {
    return "Student";
  }
}

class Employee extends Person {
  Employee() : super.init();
  
  
  String getType() {
    return "Employee";
  }
}

main() {
  Person student = Person("Student");
  Person employee = Person("Employee");
  
  print("type = ${student.getType()}");
  print("type = ${employee.getType()}");
}
  • 팩토리 패턴의 개념을 알아야 팩토리 생성자를 이해할 수 있음
    • 대략 위의 코드처럼 Person 클래스의 그 자체 인스턴스 생성 대신 자식 클래스인 Student 클래스와 Employee 클래스의 인스턴스를 리턴 받음
    • 인스턴스 생성을 자식 클래스에게 위임한 것
profile
🌱 Backend-Dev | hwaya2828@gmail.com

0개의 댓글