Study Record

[Dart] 생성자들 (+ factory) 본문

Dart

[Dart] 생성자들 (+ factory)

초코초코초코 2023. 4. 13. 18:27
728x90

🎁 생성자

클래스가 생성될 때 생성자를 부르면서 인스턴스가 생성된다. 기본적으로 상속받은 클래스가 슈퍼 클래스(super)의 생성자를 상속받지 않는다. 따라서 상속받은 클래스는 생성자를 선언하지 않으면 기본생성자(Default Constructors)만 가진다. 따라서 상속을 사용하는 클래스일 경우 슈퍼래스(상속하는 클래스)의 생성자를 직접 실행하는 작업이 필요하다.

 

 

클래스 생성자 기본 모양

class Person {
  bool isMan = false;
  
  Person(bool isMan) {
    this.isMan = isMan;
  }
} 

class Student extends Person {
  String name;
  
  // this 키워드를 사용하여 직접 사용
  Student(this.name, bool isMan) : super(isMan);
}

class Student2 extends Person {
  String name;
  
  // this 키워드와 super 키워드 사용 
  Student2(super.isMan, {required this.name});
}

void main() {
  final student2 = Student2(false, name: "하하하");
}

Person 의 생성자가 기본 모양이며 Student 와 Student2 처럼 this 키워드와 super 키워드를 직접 사용하여 바로 생성자를 선언할 수 있다.

 

 

😶 Default constructors

생성자를 선언하지 않으면 제공되는 생성자로, 인수(argument)가 없는 생성자를 호출한다.

 

😶 Named constructors

이름을 붙여 명확하게 생성자를 생성할 수 있다. 여러 개의 생성자가 존재할 때 용도에 따라 명확하게 나타낼 수 있다. 다음 예시 코드에서 Student.origin() 과 Student.admin() 생성자들이 Named Constructors 이다.

class Person {
  bool isMan;
  
  Person(this.isMan);
} 

class Student extends Person {
  String name;
  
  Student(this.name, bool isMan) : super(isMan);
  
  Student.origin(this.name, bool isMan) : super(isMan);
  
  Student.admin()
    : this.name = "어드민",
      super(false);
}

void main() {
  final a = Student("dsad", true);
  final origin = Student.origin("이름", false);
  final admin = Student.admin();
}

 

 

😶 Redirecting constructors

생성자가 다른 생성자를 부를 수 있다.

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);
}

 

 

😶 factory constructors

factory 키워드가 붙은 생성자를 생성할 수 있는데 "항상 클래스의 새 인스턴스를 만들지 않는 생성자를 구현할 때는 factory 키워드를 사용한다" 라고 공식 API 사이트에 나와있다. 

 

예시 ) final 로 선언된 변수에  값을 직접 넣고 싶은 경우

class Student {
  final int id;
  final String name;
  final String gender;

  Student({
    required this.id,
    required this.name,
    required this.gender,
  });

  factory Student.fromJson(Map<String, dynamic> json) {
    return Student(
      id: json['id'],
      name: json['name'],
      gender: json['gender'],
    );
  }
}

void main() {
  final jsonData = {
    "id" : 1,
    "name" : "fdsf",
    "gender" : "여",
  };
  
  final student = Student(
    id: jsonData['id'] as int,
    name: jsonData['name'] as String,
    gender: jsonData['gender'] as String,
  );
  
  final studentF = Student.fromJson(jsonData);
  
  print("student : [${student.id}, ${student.name}, ${student.gender}]");
  print("studentF : [${studentF.id}, ${studentF.name}, ${studentF.gender}]");
}

만약 서버에서 받아온 데이터가 main 함수의 jsonData 라고 가정해 보면, jsonData 를 Student 클래스에 데이터를 넣고 싶을 때 직접 Student() 생성자를 사용하는 것보다 factory 를 사용한 Student.fromJson 생성자에 바로 jsonData 를 넣는 것이 더 편할 것이다. 그럴 때, factory 키워드를 사용하면 final 변수들에 값을 선언할 수 있다.

 

물론, factory 키워드 없이 final 변수들을 사용하지 않으면 Named Constructors 로 생성자를 만들 수 있다.

class Student {
  int id = 0;
  String name = "none";
  String gender = "남";

  Student({
    required this.id,
    required this.name,
    required this.gender,
  });
  
  Student.fromJsonG(Map<String, dynamic> json) {
    this.id = json['id'];
    this.name = json['name'];
    this.gender = json['gender'];
  }
}

 

 

예시 ) 캐시를 사용하여 이전에 선언한 인스턴스를 리턴하는 경우 - API 문서 참고

class Logger {
  final String name;
  int num = 0;

  // _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() {
    print("$name $num");
  }
}

void main() {
  final love = Logger("love");
  final like = Logger("like");
  
  love.num = 100;
  
  final love2 = Logger("love");
  
  love.log();
  love2.log();
  like.log();
}

factory 키워드와 캐시로 이전에 생성한 인스턴스를 다시 리턴할 수 있다. 기본 생성자라면 클래스를 생성하는 순간 새로운 인스턴스가 생성되지만 factory 키워드로 인스턴스를 생성하는 것이 아닌 캐시(_cache.putIfAbsent()) 에 이전에 생성된 인스턴스를 가져올 수 있다.

 

 

 

Constructors

Everything about using constructors in Dart.

dart.dev

 

 

728x90

'Dart' 카테고리의 다른 글

[Dart] 다수의 비동기 요청 병렬로 처리하기  (0) 2023.03.17
[Dart] Enum type  (0) 2023.03.16
[Dart] 간결한 if 문 (c ? ep1 : ep2 , ep1 ?? ep2)  (0) 2023.03.16
[Dart] ..  (0) 2023.03.09
[Dart] 난수 생성하기  (0) 2023.02.05