Menu
CoddyTech

Hàm khởi tạo và kế thừa

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 41 trên 110.

Khi một lớp con (child class) kế thừa lớp cha, bạn phải gọi hàm khởi tạo (constructor) của lớp cha để khởi tạo đúng cách các trường kế thừa. Dart cung cấp nhiều cách linh hoạt để xử lý việc này thông qua danh sách khởi tạo (initializer list) bằng super.

Nếu lớp cha có hàm khởi tạo nhận tham số, lớp con phải gọi hàm đó một cách tường minh:

class Person {
  String name;
  int age;
  
  Person(this.name, this.age);
}

class Student extends Person {
  String school;
  
  Student(String name, int age, this.school) : super(name, age);
}

Dart 2.17 giới thiệu tham số super, một cú pháp gọn gàng hơn, chuyển tiếp tham số trực tiếp đến hàm khởi tạo của lớp cha:

class Student extends Person {
  String school;
  
  // super.name và super.age được truyền trực tiếp đến hàm khởi tạo (constructor) của Person
  Student(super.name, super.age, this.school);
}

Khi làm việc với các hàm khởi tạo có tên, bạn chỉ định hàm khởi tạo của lớp cha cần gọi:

class Employee extends Person {
  String department;
  
  Employee(super.name, super.age, this.department);
  
  Employee.intern(String name, this.department) : super(name, 18);
}

Quy tắc chính rất đơn giản: lớp cha phải được khởi tạo đầy đủ trước khi lớp con thêm các thuộc tính của riêng nó. Dù bạn dùng lời gọi super() truyền thống hay các tham số super mới hơn, Dart đều đảm bảo chuỗi kế thừa được tạo đúng cách từ lớp cha đến lớp con.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống quản lý kho sản phẩm để minh họa cách hàm khởi tạo hoạt động với tính kế thừa. Bạn sẽ tạo một hệ thống phân cấp, trong đó các loại sản phẩm khác nhau kế thừa từ lớp sản phẩm cơ sở và cần được khởi tạo đúng cách thông qua hàm khởi tạo của lớp cha.

Bạn sẽ sắp xếp code vào hai tệp:

  • product.dart: Định nghĩa hệ thống phân cấp sản phẩm tại đây:
    • Một lớp Product có các thuộc tính String name và double price, một hàm khởi tạo nhận cả hai giá trị và một phương thức info() in ra [name]: $[price]
    • Một lớp Book kế thừa Product và bổ sung thuộc tính String author. Dùng tham số super để chuyển tiếp name và price đến hàm khởi tạo của lớp cha
    • Một lớp Electronics kế thừa Product và bổ sung thuộc tính int warranty (tính theo tháng). Dùng lời gọi super() theo cách truyền thống trong danh sách khởi tạo để truyền các giá trị đến lớp cha
  • main.dart: Nhập tệp sản phẩm và minh họa cả hai cách kế thừa hàm khởi tạo:
    • Tạo một Book có tên 'Dart Essentials', giá 29.99 và tác giả 'Jane Smith'
    • Gọi phương thức info() của đối tượng, rồi in ra Author: [author]
    • In ra một dòng trống
    • Tạo một Electronics có tên 'Wireless Mouse', giá 45.50 và thời hạn bảo hành 24
    • Gọi phương thức info() của đối tượng, rồi in ra Warranty: [warranty] months

Cả hai lớp con đều kế thừa phương thức info() từ Product mà không cần ghi đè phương thức này. Điểm khác biệt chính nằm ở cách chúng gọi hàm khởi tạo của lớp cha: Book dùng cú pháp tham số super gọn hơn, còn Electronics dùng cách truyền thống với super() trong danh sách khởi tạo.

Đầu ra dự kiến:

Dart Essentials: $29.99
Author: Jane Smith

Wireless Mouse: $45.5
Warranty: 24 months

Tự làm thử

import 'product.dart';

void main() {
  // TODO: Tạo một Book với:
  // - name: 'Dart Essentials'
  // - price: 29.99
  // - author: 'Jane Smith'

  // TODO: Gọi phương thức info() của Book

  // TODO: In ra "Author: [author]"

  // TODO: In ra một dòng trống

  // TODO: Tạo một Electronics với:
  // - name: 'Wireless Mouse'
  // - price: 45.50
  // - warranty: 24

  // TODO: Gọi phương thức info() của Electronics

  // TODO: In ra "Warranty: [warranty] months"
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online