openplanning

Constructor trong Dart

  1. Constructor là gì?
  2. Constructor - Syntax 1
  3. Constructor - Syntax 2
  4. Constructor - Syntax 3
  5. Constructor - Mix Syntax
  6. Trường tuỳ chọn
  7. External factory constructor

1. Constructor là gì?

Constructor là một hàm đặc biệt của lớp, được sử dụng để tạo ra đối tượng và khởi tạo các giá trị cho các trường (field).
Để đơn giản, chúng ta sẽ phân tích tình huống dưới đây:
class Person {
   String name;
   String gender;
   String country;
   // Other members..
}
Lớp Person được coi là một bản thiết kế để tạo ra các con người cụ thể. Nó bao gồm các thông tin: Tên, giới tính và quốc gia. Các thông tin này còn được gọi là các trường (field).
Constructor là hàm đặc biệt để tạo ra một đối tượng và gán giá trị cụ thể cho các trường.
Quy tắc đặt tên cho Constructor:
  • Class_Name(arguments)
  • Class_Name.extension_name1(arguments)
  • Class_Name.extension_name2(arguments)
Đặc điểm của Constructor:
  • Một lớp có thể có một hoặc nhiều constructor.
  • Trong một lớp không thể có 2 constructor cùng tên, kể cả chúng có các tham số khác nhau.
  • Nếu bạn không định nghĩa bất kỳ constructor nào cho một lớp, Dart sẽ tự động coi rằng lớp này có một constructor mặc định, không tham số và không có nội dung trong thân.
Syntax:
  • Về cơ bản, có 3 cú pháp chính để khai báo một constructor, và một cú pháp pha trộn của 3 cú pháp trên (Xem chi tiết bên dưới).
Ngôn ngữ Dart được thiết kế chặt chẽ và an toàn, nó đòi hỏi tất các trường (field) của lớp phải được gán giá trị khác null. Nếu một một trường nào đó cho phép giá trị null bạn phải nói rõ điều đó trong thiết kế của lớp.

2. Constructor - Syntax 1

Đây là cú pháp của constructor được khuyến khích sử dụng:
Constructor Syntax 1
class Class_name {
    field1;
    field2;
    fieldN;

    // Constructor
    Class_name(arg1, arg2, argN) :
         field1 = arg1,
         field2 = arg2,
         fieldN = argN {
         // (Constructor body)
         // Other code ...
   }
}
Theo cú pháp này, các trường sẽ được gán giá trị tại khối khởi tạo (Initial block). Khối này đứng trước thân của constructor. Code trong khối khởi tạo sẽ được thực thi trước so với code trong thân của constructor.
Ví dụ:
constructor_syntax1_ex1.dart
class Person {
  String name;
  String gender;
  String country;

  // Constructor:
  Person(String n, String g, String c)
      : name = n,
        gender = g,
        country = c {
    // (Constructor body)
    // Other codes ...
  }

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

void main()  {
   Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
   emma.selfIntroduce(); // Call method.

   Person jack = Person('Jack', 'Male', 'USA'); // Create an object
   jack.selfIntroduce();

   var hong = Person('Hong', 'Female', 'Vietnam'); // Create an object
   hong.selfIntroduce();
}
Output:
Hi, My name is Emma, Female, from USA
Hi, My name is Jack, Male, from USA
Hi, My name is Hong, Female, from Vietnam
Đôi khi tên của các trường và tên các tham số trong constructor trùng nhau, điều này không gây ra sự nhầm lẫn vì trình biên dịch của Dart đủ thông minh.
constructor_syntax1_ex1b.dart
class Person {
  String name;
  String gender;
  String country;

  // Constructor:
  Person(String name, String gender, String c)
      : name = name,
        gender = gender,
        country = c {
    // (Constructor body)
    // Other codes ...
  }

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}
Nếu thân của constructor không có nội dung, bạn có thể loại bỏ nó. Ví dụ trên có thể được viết ngắn gọn hơn như thế này:
constructor_syntax1_ex1c.dart
class Person {
  String name;
  String gender;
  String country;

  // Constructor:
  Person(String name, String gender, String c)
      : name = name,
        gender = gender,
        country = c;

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

3. Constructor - Syntax 2

Cú pháp dưới đây là một cải tiến ngắn gọn hơn cho cú pháp trước.
Constructor Syntax 2
class Class_name {
    field1;
    field2;
    fieldN;

    // Constructor
    Class_name(this.field1, this.field2, this.fieldN)  {
         // (Constructor body)
         // Other code ...
   }
}
Ví dụ:
constructor_syntax2_ex1.dart
class Person {
  String name;
  String gender;
  String country;

  // Constructor:
  Person(this.name, this.gender, this.country) {
    // (Constructor body)
    // Other codes ...
  }

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

void main() {
  Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
  emma.selfIntroduce(); // Call method.

  Person jack = Person('Jack', 'Male', 'USA'); // Create an object
  jack.selfIntroduce();

  var hong = Person('Hong', 'Female', 'Vietnam'); // Create an object
  hong.selfIntroduce();
}
Nếu thân của constructor không có nội dung, bạn có thể loại bỏ nó. Ví dụ trên có thể được viết ngắn gọn hơn như thế này:
constructor_syntax2_ex1b.dart
class Person {
  String name;
  String gender;
  String country;

  // Constructor:
  Person(this.name, this.gender, this.country);

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

void main() {
  Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
  emma.selfIntroduce(); // Call method.

  Person jack = Person('Jack', 'Male', 'USA'); // Create an object
  jack.selfIntroduce();

  var hong = Person('Hong', 'Female', 'Vietnam'); // Create an object
  hong.selfIntroduce();
}

4. Constructor - Syntax 3

Cú pháp này khởi tạo giá trị cho các trường tại thân của constructor. Vì vậy cần từ khoá "late" đặt trước các trường để nói với Dart rằng "OK tôi sẽ gán giá trị cho các trường này muộn một chút".
Constructor Syntax 3
class Class_name {
    late field1;
    late field2;
    late fieldN;

    // Constructor
    Class_name(arg1, arg2, argN)  { // (Constructor body)
         field1 = arg1;
         field2 = arg2;
         fieldN = argN;
         // Other code ...
   }
}
Ví dụ:
constructor_syntax3_ex1.dart
class Person {
  late String name;
  late String gender;
  late String country;

  // Constructor:
  Person(String n, String g, String c) {
    // (Constructor body)
    name = n;
    gender = g;
    country = c;
    // Other codes ...
  }

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

void main() {
  Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
  emma.selfIntroduce(); // Call method.

  Person jack = Person('Jack', 'Male', 'USA'); // Create an object
  jack.selfIntroduce();

  var hong = Person('Hong', 'Female', 'Vietnam'); // Create an object
  hong.selfIntroduce();
}

5. Constructor - Mix Syntax

Bạn có thể phan trộn 3 cú pháp ở trên để tạo ra một cú pháp mới.
Constructor - Mix Syntax
class Class_name {
    field1;
    field2;
    late fieldN;

    // Constructor
    Class_name(arg1, this.field2, argN) :
         field1 = arg1 { // (Constructor body)
         fieldN = argN;
         // Other code ...
   }
}
Ví dụ:
constructor_mix_syntax_ex1.dart
class Person {
  String name;
  String gender;
  late String country;

  // Constructor:
  Person(String n, this.gender, String c) :
   name = n {  // (Constructor body)  
    country = c;
    // Other codes ...
  }

  // Method:
  void selfIntroduce() {
    print('Hi, My name is $name, $gender, from $country');
  }
}

void main() {
  Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
  emma.selfIntroduce(); // Call method.

  Person jack = Person('Jack', 'Male', 'USA'); // Create an object
  jack.selfIntroduce();

  var hong = Person('Hong', 'Female', 'Vietnam'); // Create an object
  hong.selfIntroduce();
}

6. Trường tuỳ chọn

Theo mặc định, Dart đòi hỏi tất cả các trường (field) của lớp cần được gán giá trị trong quá trình khởi tạo đối tượng. Nếu một trường nào đó chấp nhận giá trị null bạn phải nói rõ điều đó trong định nghĩa của lớp.
Sử dụng dấu chấm hỏi ( ? ) để nói với Dart rằng "Đây là một trường cho phép giá trị null":
constructor_optional_props_ex1.dart
class Person {
  late String name;
  String gender = 'Male'; // Field with default value
  String? country; // Allow null value!

  // Constructor:
  Person(String n, String g, String c) {
    name = n;
    gender = g;
    country = c;
  }
  // Constructor:
  Person.nameOnly(String n) {
    name = n;
  }

  // Method:
  void selfIntroduce() {
    if (country != null) {
      print('Hi, My name is $name, $gender, from $country');
    } else {
      print('Hi, My name is $name');
    }
  }
}

void main() {
  Person emma = new Person('Emma', 'Female', 'USA'); // Create an object
  emma.selfIntroduce(); // Call method.

  Person jack = Person.nameOnly('Jack'); // Create an object
  jack.selfIntroduce();
}
Output:
Hi, My name is Emma, Female, from USA
Hi, My name is Jack

7. External factory constructor

  • TODO: Chém gió về cái này!