Giới thiệu về Mixin
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 50 trên 110.
Bạn đã học rằng Dart chỉ cho phép kế thừa một lớp. Dù có thể triển khai nhiều giao diện, bạn vẫn phải tự viết toàn bộ code. Nhưng nếu bạn muốn chia sẻ phần code triển khai thực tế giữa nhiều lớp không liên quan thì sao? Đây là lúc mixin (mixin) phát huy tác dụng.
Mixin là một cách để tái sử dụng code trong nhiều hệ phân cấp lớp. Hãy hình dung nó như một tập hợp các phương thức và thuộc tính mà bạn có thể “trộn vào” bất kỳ lớp nào, giúp lớp đó có thêm khả năng mà không cần dùng đến kế thừa.
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}
void main() {
var duck = Duck();
duck.quack();
duck.swim(); // Từ mixin
var fish = Fish();
fish.swim(); // Cùng cách triển khai, khác lớp
}Hãy chú ý đến từ khóa with. Đây là cách bạn áp dụng một mixin cho lớp. Khác với implements, bạn không cần tự viết phương thức. Mixin cung cấp đoạn code thực tế, và lớp của bạn tự động có chức năng đó.
Mixin giải quyết một vấn đề thực tế: Duck và Fish không có quan hệ kế thừa, nhưng cả hai đều cần khả năng bơi. Với mixin, bạn viết code một lần rồi dùng lại ở bất cứ đâu cần đến.
Thử thách
DễHãy xây dựng một hệ thống nhạc cụ để tìm hiểu cách mixin giúp bạn chia sẻ hành vi giữa các lớp không liên quan với nhau. Bạn sẽ tạo một mixin cung cấp chức năng lên dây, rồi áp dụng nó cho các nhạc cụ khác nhau không có quan hệ kế thừa.
Bạn sẽ sắp xếp code vào hai tệp:
instruments.dart: Định nghĩa mixin và các lớp nhạc cụ tại đây:- Một mixin
Tunablecó phương thứctune()in raTuning the instrument...và phương thứccheckTuning()in raTuning is perfect! - Một lớp
Guitarsử dụng mixinTunable. Thêm thuộc tínhString brandcùng hàm khởi tạo. Thêm phương thứcstrum()in ra[brand] guitar strumming chords - Một lớp
Pianocũng sử dụng mixinTunable. Thêm thuộc tínhint keyscùng hàm khởi tạo. Thêm phương thứcplay()in raPlaying [keys]-key piano
- Một mixin
main.dart: Nhập tệp nhạc cụ và minh họa cách cả hai nhạc cụ không liên quan đều có khả năng lên dây nhờ cùng một mixin:- Tạo một
Guitarcó nhãn hiệu'Fender' - Tạo một
Pianocó88phím - Với guitar: gọi
tune(), rồistrum(), sau đócheckTuning() - In ra một dòng trống
- Với piano: gọi
tune(), rồiplay(), sau đócheckTuning()
- Tạo một
Hãy để ý rằng Guitar và Piano là hai nhạc cụ hoàn toàn khác nhau, không có quan hệ kế thừa, nhưng cả hai đều có cùng các phương thức lên dây nhờ mixin Tunable. Bạn chỉ cần viết code lên dây một lần, rồi cả hai lớp đều có thể sử dụng code đó với từ khóa with.
Đầu ra dự kiến:
Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!
Tuning the instrument...
Playing 88-key piano
Tuning is perfect!Tự làm thử
import 'instruments.dart';
void main() {
// TODO: Tạo một Guitar có thương hiệu 'Fender'
// TODO: Tạo một Piano có 88 phím
// TODO: Với đàn guitar, gọi tune(), rồi strum(), sau đó checkTuning()
// TODO: In ra một dòng trống
// TODO: Với đàn piano, gọi tune(), rồi play(), sau đó checkTuning()
}
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
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiThư viện và câu lệnh importGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcBiến thể hiệnKiến thức cơ bản về hàm khởi tạoÔn tập: Máy tính đơn giản4An toàn với giá trị null
Giới thiệu về an toàn với giá trị nullCó thể null và không thể nullToán tử ? và !Từ khóa late và an toàn với giá trị nullToán tử xử lý nullAn toàn với giá trị null trong lớpÔn tập: hệ thống hồ sơ người dùng7Lớp trừu tượng và interface
Lớp trừu tượngPhương thức trừu tượngInterface trong DartInterface ngầm địnhTriển khai và kế thừaNhiều interfaceÔn tập: Máy tính hình10Bộ sưu tập và kiểu tổng quát
Tổng quan về List, Set và MapBộ sưu tập an toàn về kiểuLớp tổng quátPhương thức tổng quátRàng buộc kiểu tổng quátIterable và IteratorÔn tập: Lưu trữ tổng quát2Hàm khởi tạo trong Dart
Hàm khởi tạo mặc địnhHàm khởi tạo có tênDanh sách khởi tạoHàm khởi tạo hằng sốHàm khởi tạo nhà máyHàm khởi tạo chuyển hướngÔn tập: Trình tạo hình dạng5Đóng gói
Thành viên công khai và riêng tưQuy ước tiền tố _Tính riêng tư ở cấp thư việnTìm hiểu sâu về getter và setterChe giấu thông tinÔn tập: hồ sơ học sinh8Mixin
Giới thiệu về MixinTạo MixinSử dụng nhiều MixinTừ khóa on trong MixinMixin và kế thừaMixin và giao diệnÔn tập: hệ thống động vật3Thuộc tính của lớp
Thành viên instance và thành viên tĩnhTrường final và constBiến latePhương thức và trường tĩnhGetter và setterÔn tập: trình quản lý tài khoản ngân hàng6Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChú thích @overrideTừ khóa lớp finalHàm khởi tạo và kế thừaÔn tập: phân cấp nhân viên9Đa hình
Khái niệm cơ bản về đa hìnhĐa hình qua giao diệnKiểm tra kiểu lúc chạyToán tử is và asTừ khóa hiệp biếnÔn tập: Bộ xử lý thanh toánTự luyện tập: Trình biên dịch Dart online