Mẫu tổng hợp
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 99 trên 110.
Mẫu Composite cho phép bạn xử lý các đối tượng riêng lẻ và nhóm đối tượng theo cùng một cách. Mẫu này kết hợp các đối tượng thành cấu trúc cây, trong đó cả phần tử đơn lẻ và tập hợp phần tử đều dùng chung một giao diện. Mẫu này rất phù hợp để biểu diễn các cấu trúc phân cấp như hệ thống tệp, sơ đồ tổ chức hoặc thành phần giao diện người dùng.
Mẫu này có hai loại thành phần tham gia: các nút Leaf (đối tượng riêng lẻ không có nút con) và các nút Composite (vùng chứa các thành phần khác). Cả hai đều triển khai giao diện Component chung:
abstract class FileSystemItem {
String get name;
int getSize();
void display([String indent = '']);
}
class File implements FileSystemItem {
@override
final String name;
final int size;
File(this.name, this.size);
@override
int getSize() => size;
@override
void display([String indent = '']) {
print('$indent- $name ($size KB)');
}
}
class Folder implements FileSystemItem {
@override
final String name;
final List<FileSystemItem> _children = [];
Folder(this.name);
void add(FileSystemItem item) => _children.add(item);
@override
int getSize() => _children.fold(0, (sum, item) => sum + item.getSize());
@override
void display([String indent = '']) {
print('$indent+ $name/');
for (var child in _children) {
child.display('$indent ');
}
}
}
void main() {
var docs = Folder('Documents');
docs.add(File('resume.pdf', 150));
docs.add(File('photo.jpg', 2400));
var projects = Folder('Projects');
projects.add(File('main.dart', 25));
docs.add(projects);
docs.display();
print('Total: ${docs.getSize()} KB');
}Lớp Folder có thể chứa cả các đối tượng File lẫn các đối tượng Folder khác. Khi bạn gọi getSize() trên một thư mục, hàm này tính đệ quy tổng kích thước của toàn bộ nội dung bên trong. Code phía client không cần biết nó đang làm việc với một tệp riêng lẻ hay cả một hệ thống thư mục phân cấp, cả hai đều phản hồi cùng các phương thức.
Thử thách
DễHãy cùng xây dựng một hệ thống sơ đồ tổ chức bằng mẫu Composite! Bạn sẽ tạo một cấu trúc trong đó nhân viên riêng lẻ và các phòng ban (có nhân viên và phòng ban khác bên trong) đều có thể được xử lý thống nhất, rất phù hợp để biểu diễn hệ thống phân cấp của công ty.
Bạn sẽ tổ chức code thành hai tệp:
organization.dart: Tệp này chứa giao diện thành phần cùng với các lớp lá và lớp tổ hợp. Tạo một lớp trừu tượngOrganizationUnitcó gettername, phương thứcgetSalaryBudget()trả về kiểuintvà phương thứcdisplay([String indent = ''])để hiển thị hệ thống phân cấp. Xây dựng lớpEmployee(lớp lá) triển khaiOrganizationUnit. Lớp này cần có tên và mức lương, trong đógetSalaryBudget()trả về mức lương của nhân viên.display()cần in ra[indent]- [name] ($[salary]). Tiếp theo, tạo lớpDepartment(lớp tổ hợp), cũng triển khaiOrganizationUnit. Lớp này cần có tên và duy trì một danh sách phần tử con thuộc kiểuOrganizationUnit. Thêm phương thứcadd()để đưa nhân viên hoặc phòng ban phụ vào.getSalaryBudget()cần tính tổng ngân sách của tất cả phần tử con bằng đệ quy.display()cần in ra[indent]+ [name]/, sau đó hiển thị từng phần tử con với mức thụt lề tăng lên (thêm hai dấu cách).main.dart: Nhập tệp tổ chức của bạn và xây dựng cấu trúc công ty. Tạo phòng banEngineeringgồm hai nhân viên:Alicecó mức lương80000vàBobcó mức lương75000. Tạo phòng banQAvới một nhân viên:Carolcó mức lương65000. Tiếp theo, tạo phòng banTechnologyvà thêm cảEngineeringlẫnQAlàm phòng ban phụ. Gọidisplay()trên phòng ban Technology, sau đó in raTotal Budget: $theo sau là tổng ngân sách tiền lương.
Điểm hay của mẫu Composite là Technology.getSalaryBudget() tự động tính tổng của tất cả phòng ban lồng nhau và nhân viên, code phía gọi không cần biết cấu trúc bên trong!
Đầu ra dự kiến:
+ Technology/
+ Engineering/
- Alice ($80000)
- Bob ($75000)
+ QA/
- Carol ($65000)
Total Budget: $220000Tự làm thử
import 'organization.dart';
void main() {
// TODO: Tạo một phòng ban Engineering
// TODO: Thêm Alice với mức lương 80000
// TODO: Thêm Bob với mức lương 75000
// TODO: Tạo một phòng ban QA
// TODO: Thêm Carol với mức lương 65000
// TODO: Tạo một phòng ban Technology
// TODO: Thêm Engineering và QA làm các phòng ban trực thuộc
// TODO: Gọi display() trên phòng ban Technology
// TODO: In ra "Total Budget: $", sau đó là tổng ngân sách lương
}
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án12OOP bất đồng bộ
Future và async/awaitCơ bản về StreamBộ điều khiển StreamHàm khởi tạo bất đồng bộBất đồng bộ trong phương thức lớpÔn tập: Trình lấy dữ liệu15Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổng hợpMẫu RepositoryTự luyện tập: Trình biên dịch Dart online