Giới thiệu
Trong cuộc sống hàng ngày, chúng ta thực hiện nhiều công việc giống nhau một cách tự động như thức dậy, đánh răng, rửa mặt, ăn sáng, và đi làm. Những hành động lặp đi lặp lại này chính là ví dụ minh họa cho việc xây dựng một bộ khung làm việc. Điều này có thể được so sánh với một Template Method trong lập trình, nơi chúng ta có thể định nghĩa một chu trình công việc mà không bị ảnh hưởng bởi những thay đổi của từng chức năng xuyên suốt.
Template Method là gì?
Mẫu thiết kế Template Method thuộc loại behavioral và được phát triển để xác định một bộ khung cho các thuật toán, nhằm giảm thiểu việc lặp mã (code duplication) và cho phép các lớp con điều chỉnh hành vi mà không làm ảnh hưởng đến cấu trúc chính.
Công dụng và lý do tồn tại
Mẫu Template Method cung cấp hai lợi ích chính:
- Tạo ra một nền tảng mà các lớp con có thể tuân theo, giúp tránh lặp lại mã.
- Cho phép các lớp con cài đặt lại các phương thức đã được định nghĩa mà không làm thay đổi lớp cơ sở.
Sơ đồ lớp của Template Method
Mô hình triển khai Template Method được thể hiện qua sơ đồ lớp dưới đây:
- AbstractClass: Lớp trừu tượng chứa phương thức
templateMethod()
, định nghĩa quy trình thuật toán. Phương thức này sẽ gọi các phương thức khác chưa được cài đặt. - ConcreteClass: Kế thừa từ lớp trừu tượng và cài đặt các phương thức cụ thể.
Ứng dụng trong thực tiễn
Mẫu thiết kế Template Method được sử dụng khi cần thực hiện cùng một logic thuật toán nhưng cho nhiều lớp khác nhau. Chẳng hạn, khi xử lý nhiều định dạng file khác nhau như PDF, Excel, hay Word. Với mỗi loại file, ta có thể sử dụng cùng một quy trình xử lý mà không phải viết lại mã cho từng định dạng.
Hướng dẫn triển khai
Giả sử chúng ta có nhiều trang với tiêu đề chung và cần hiển thị UI Loading mỗi khi tải dữ liệu từ API. Với việc xây dựng một lớp trừu tượng, ta sẽ có thể khai báo tiêu đề và UI Loading một cách chung nhất mà không cần lặp lại mã cho từng trang khác nhau.
Dưới đây là ví dụ cho một lớp trừu tượng TemplateMethodBaseStateBody:
dart
abstract class TemplateMethodBaseStateBody<T extends StatefulWidget> extends State<T> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const PrimaryAppBar(
title: 'Template Method',
),
body: Stack(
children: [
buildBody(context),
Visibility(
visible: isLoading,
child: buildLoading(),
),
],
),
);
}
Widget buildBody(BuildContext context);
Widget buildLoading() => const Center(
child: CircularProgressIndicator(),
);
bool get isLoading => false;
}
Với đoạn code trên, ta đã tạo ra một bộ khung với tiêu đề và UI Loading. Thông qua việc định nghĩa phương thức buildBody
, mỗi trang cụ thể chỉ cần cài đặt riêng nội dung bên trong mà không làm ảnh hưởng đến các thành phần khác.
Dưới đây là cách khai báo một trang cụ thể TemplateMethodPage:
dart
class TemplateMethodPage extends StatefulWidget {
const TemplateMethodPage({super.key});
@override
State<TemplateMethodPage> createState() => _TemplateMethodPageState();
}
class _TemplateMethodPageState extends TemplateMethodBaseStateBody<TemplateMethodPage> {
bool isShowLoading = false;
@override
bool get isLoading => isShowLoading;
@override
Widget buildBody(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: ElevatedButton(
onPressed: () {
setState(() {
isShowLoading = !isShowLoading;
});
},
child: Text(!isShowLoading ? 'Show loading' : 'Hide loading'),
),
);
}
}
Thông qua hệ thống kế thừa thông minh này, chúng ta có thể xây dựng từng trang với nội dung khác nhau mà không phải lo lắng về việc lặp lại mã đã viết trước đó.
Kết quả đạt được
Với phương pháp Template Method, mỗi khi cần trang nào cũng có UI Loading hay một tiêu đề chung, chỉ cần kế thừa lớp trừu tượng đã tạo, rất tiện lợi và hiệu quả.
Kết luận
Template Method là một giải pháp linh hoạt giúp chúng ta tối ưu hóa mã nguồn, giảm thiểu sự trùng lặp và hạn chế sai sót trong quá trình phát triển. Trong bài tiếp theo, chúng ta sẽ khám phá một mẫu thiết kế mới: Cây Cấu Trúc - Composite - "Chúng Sinh Bình Đẳng".
source: viblo