Menu
CoddyTech

Mixin 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 54 trên 110.

Giờ bạn đã biết mixin hoạt động như thế nào, hãy cùng làm rõ khi nào nên dùng chúng thay vì kế thừa. Điểm khác biệt chính nằm ở mối quan hệ mà chúng thể hiện.

Kế thừa thể hiện mối quan hệ "là một". Một Dog là một Animal. Lớp con là phiên bản chuyên biệt của lớp cha, và bạn chỉ có thể mở rộng một lớp.

Ngược lại, mixin thể hiện mối quan hệ về khả năng làm được điều gì đó. Dog có thể bơi, nhưng bơi không phải là điều định nghĩa một chú chó.

// Kế thừa (inheritance): Dog là một Animal
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

// Mixin: Dog có thể bơi (nhưng khả năng bơi không quyết định Dog là gì)
mixin Swimming {
  void swim() => print('Swimming');
}

class Dog extends Animal with Swimming {
  Dog(String name) : super(name);
}

Dùng kế thừa khi các lớp có chung bản chất cơ bản và bạn cần hàm khởi tạo trong lớp cha. Dùng mixin khi bạn muốn bổ sung khả năng cho các lớp không có chung lớp tổ tiên.

Tính năngKế thừaMixin
Mối quan hệlà mộtcó thể làm
Giới hạnChỉ một lớp chaNhiều mixin
Hàm khởi tạoĐược phépKhông được phép
Trường hợp sử dụngChuyên biệt hóaHành vi dùng chung

Điều tuyệt nhất là bạn có thể kết hợp cả hai: kế thừa một lớp và bổ sung nhiều khả năng, giúp các lớp có chính xác những tính năng cần thiết.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống nhân viên để minh họa khi nào nên dùng kế thừa và khi nào nên dùng mixin. Bạn sẽ tạo một lớp cơ sở cho mối quan hệ “là một” và các mixin cho những khả năng “có thể làm”, sau đó kết hợp chúng để cho thấy hai cách tiếp cận này phối hợp với nhau như thế nào.

Bạn sẽ sắp xếp code thành ba tệp:

  • worker.dart: Định nghĩa lớp cơ sở xác định danh tính cốt lõi của tất cả nhân viên:
    • Một lớp Worker có các thuộc tính String name và String department. Thêm hàm khởi tạo nhận cả hai giá trị. Thêm phương thức introduce() in ra [name] works in [department]
  • skills.dart: Định nghĩa các mixin thể hiện những khả năng mà nhân viên có thể có (mối quan hệ “có thể làm”):
    • Một mixin CanCode có phương thức writeCode() in ra Writing code...
    • Một mixin CanDesign có phương thức createDesign() in ra Creating design...
    • Một mixin CanManage có phương thức leadTeam() in ra Leading the team...
  • main.dart: Nhập cả hai tệp và tạo các kiểu nhân viên chuyên biệt kết hợp kế thừa với mixin:
    • Một lớp Developer mở rộng Worker và dùng mixin CanCode
    • Một lớp TechLead mở rộng Worker và dùng cả hai mixin CanCode và CanManage
    • Tạo một Developer tên là 'Alice' thuộc phòng ban 'Engineering'
    • Tạo một TechLead tên là 'Bob' thuộc phòng ban 'Engineering'
    • Với Alice: gọi introduce(), sau đó gọi writeCode()
    • In ra một dòng trống
    • Với Bob: gọi introduce(), sau đó gọi writeCode(), rồi gọi leadTeam()

Hãy chú ý rằng cả Developer và TechLead đều là nhân viên (kế thừa), nhưng họ có thể làm những việc khác nhau (mixin). TechLead kết hợp nhiều khả năng mà không cần dùng đa kế thừa.

Kết quả mong đợi:

Alice works in Engineering
Writing code...

Bob works in Engineering
Writing code...
Leading the team...

Tự làm thử

import 'worker.dart';
import 'skills.dart';

// TODO: Tạo lớp Developer kế thừa Worker và dùng mixin CanCode

// TODO: Tạo lớp TechLead kế thừa Worker và dùng cả hai mixin CanCode và CanManage

void main() {
  // TODO: Tạo một Developer tên 'Alice' thuộc bộ phận 'Engineering'
  
  // TODO: Gọi introduce(), rồi writeCode() cho Alice
  
  // TODO: In ra một dòng trống
  
  // TODO: Tạo một TechLead tên 'Bob' thuộc bộ phận 'Engineering'
  
  // TODO: Gọi introduce(), writeCode(), rồi leadTeam() cho Bob
}
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