Mẫu Iterator
Thuộc phần Lập trình hướng đối tượng trong hành trình C của Coddy. Bài học 56 trên 61.
Mẫu thiết kế Iterator pattern cung cấp cách truy cập tuần tự các phần tử trong một tập hợp mà không để lộ cấu trúc bên trong. Thay vì cho người dùng truy cập trực tiếp vào một mảng, bạn cung cấp cho họ một đối tượng biết cách duyệt qua dữ liệu từng phần tử một.
Bộ lặp thường cần hai thông tin: tham chiếu đến tập hợp và vị trí hiện tại. Trong C, ta tạo một struct để lưu trạng thái này:
typedef struct {
int* data; // con trỏ đến mảng
int size; // tổng số phần tử
int current; // vị trí hiện tại
} IntIterator;Trình lặp cung cấp hai hàm chính. has_next() kiểm tra xem còn phần tử nào để đọc không, còn next() trả về phần tử hiện tại và chuyển vị trí tiến lên:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}Dùng trình lặp giúp code gọn gàng và ẩn đi các chi tiết về mảng:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}Bên gọi không cần biết numbers là một mảng hay cách truy cập bằng chỉ số hoạt động. Sự trừu tượng hóa này giúp bạn dễ dàng thay đổi cấu trúc dữ liệu bên dưới sau này, chẳng hạn từ mảng sang danh sách liên kết, mà không cần sửa code sử dụng trình lặp.
Thử thách
DễHãy tạo một bộ lặp NumberList: một lớp trừu tượng gọn gàng, cho phép bạn duyệt qua một tập hợp số nguyên mà không để lộ cấu trúc mảng bên dưới.
Bạn sẽ chia code thành ba tệp:
iterator.h: Định nghĩa một structIntIteratorchứa con trỏ đến mảng số nguyên, tổng số phần tử trong tập hợp và vị trí hiện tại. Khai báo ba hàm:create_iterator(nhận con trỏ mảng và kích thước, trả về một bộ lặp đã khởi tạo),has_next(kiểm tra xem còn phần tử nào không) vànext(trả về phần tử hiện tại rồi tăng vị trí). Đừng quên các include guard!iterator.c: Cài đặt các hàm của bộ lặp. Hàmcreate_iteratorsẽ trả về mộtIntIteratortheo giá trị, với vị trí hiện tại được đặt thành 0. Hàmhas_nexttrả về 1 nếu còn phần tử để đọc, nếu không thì trả về 0. Hàmnexttrả về phần tử ở vị trí hiện tại, sau đó tăng vị trí.main.c: Đọc số lượng phần tử, sau đó đọc từng giá trị số nguyên vào một mảng. Tạo bộ lặp cho mảng này, rồi dùng vòng lặp while cùng vớihas_nextvànextđể duyệt và in từng phần tử trên một dòng riêng.
Chương trình sẽ nhận:
- Số lượng phần tử trong mảng
- Từng giá trị số nguyên trên một dòng riêng
Dùng mẫu thiết kế bộ lặp để in tất cả phần tử: không truy cập trực tiếp vào chỉ số mảng trong vòng lặp duyệt!
Đầu ra ví dụ khi đầu vào lần lượt là 4, rồi 10, 20, 30, 40:
10
20
30
40Đầu ra ví dụ khi đầu vào lần lượt là 3, rồi -5, 0, 100:
-5
0
100Đầu ra ví dụ khi đầu vào lần lượt là 1, rồi 42:
42Bộ lặp che giấu cách lưu trữ dữ liệu. Vòng lặp chính chỉ cần hỏi “còn phần tử nào không?” và “đưa phần tử tiếp theo cho mình”, mà không cần biết gì về chỉ số mảng hay cách bố trí bộ nhớ.
Tự làm thử
#include <stdio.h>
#include "iterator.h"
int main() {
int n;
scanf("%d", &n);
int arr[n];
// TODO: Đọc n giá trị số nguyên (integer) vào mảng (array)
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// TODO: Tạo bộ lặp cho mảng
// TODO: Dùng vòng lặp while với has_next và next để duyệt mảng
// và in mỗi phần tử (element) trên một dòng riêng
// KHÔNG dùng chỉ số (index) trực tiếp để truy cập mảng trong vòng lặp duyệt!
return 0;
}
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
1Kiến thức cơ bản về lập trình mô-đun
Tệp tiêu đềInclude guardTệp mã nguồnHàm staticÔn tập: Máy tính mô-đun4Tính đóng gói
Khái niệm con trỏ mờĐịnh nghĩa struct mờHàm truy xuất và hàm gánKiểm tra tính hợp lệ trong hàm gánÔn tập: Hộp bí mật2Đối tượng và phương thức
Struct dưới dạng đối tượngCon trỏ 'Self'Tính đúng đắn của constCon trỏ và giá trịPhương thức hỗ trợÔn tập: trình quản lý Point5Dự án: Tài khoản ngân hàng đơn giản
Thiết lập dự ánTriển khai tài khoản3Vòng đời đối tượng
Mẫu hàm khởi tạoMẫu hàm hủyKhởi tạo trên ngăn xếpSao chép sâuÔn tập: lớp bao bọc chuỗi6Kế thừa bằng cách kết hợp
Nhúng structQuy tắc thành viên đầu tiênTruy cập thành viên lớp chaUpcastingÔn tập: hệ phân cấp hình dạngTự luyện tập: Trình biên dịch C online