Giới thiệu về Iterator design pattern
Sử dụng các cấu trúc dữ liệu tập hợp như: array, set, map, tree, stack, queue,… là một phần không thể thiếu trong quá trình phát triển ứng dụng. Tuy nhiên, mỗi cấu trúc dữ liệu này lại có những cách lưu trữ và truy cập phần tử rất khác nhau. Vậy có cách nào để có 1 interface chung, cho phép chúng ta duyệt qua các phần tử mà không cần biết về kiểu của tập hợp không? Iterator pattern chính là câu trả lời trong tình huống này!
Iterator pattern là gì?
Iterator pattern là một Design Pattern được xếp vào nhóm hành vi (Behavioral Patterns). Như đã trình bày ở phần giới thiệu, một Iterator được thiết kế cho phép xử lý nhiều loại tập hợp khác nhau bằng cách truy cập các phần tử với cùng một phương thức định sẵn, mà không cần hiểu rõ về tập hợp gốc.
Thông thường, Iterator đã được cài đặt sẵn trong các ngôn ngữ lập trình hiện đại dưới dạng 1 interface, với 2 phương thức chính:
- next(): trả về phần tử kế tiếp trong tập hợp.
- hasNext(): trả về giá trị True nếu vẫn còn phần tử trong tập hợp, và False trong trường hợp ngược lại.
Cài đặt
Sau khi xong phần lý thuyết, chúng ta sẽ bắt tay vào cài đặt và sử dụng 1 Iterator interface đơn giản để hiểu hơn về design pattern này nhé!
Chúng ta sẽ định nghĩa 2 interface, bao gồm Container chứa phương thức khởi tạo ra iterator, và Iterator chứa các phương thức next() và hasNext() như đã giới thiệu. Để implement 2 interface này, chúng ta sẽ cần 2 class, trong đó 1 class sẽ là private class nằm trong class còn lại. Thiết kế cụ thể được mô tả trong hình sau:
Sau đây là code cụ thể của chương trình, được viết trên Java:
Iterator.java
public interface Iterator { public boolean hasNext(); public Object next(); }
Container.java
public interface Container { public Iterator getIterator(); }
NameRepository.java
public class NameRepository implements Container { public String names[] = {"Robert" , "John" ,"Julie" , "Lora"}; @Override public Iterator getIterator() { return new NameIterator(); } private class NameIterator implements Iterator { int index; @Override public boolean hasNext() { if(index < names.length){ return true; } return false; } @Override public Object next() { if(this.hasNext()){ return names[index++]; } return null; } } }
Cuối cùng, chúng ta tạo ra 1 iterator bằng cách gọi getIterator() từ 1 object NameRepository, sau đó test 2 phương thức next() và hasNext() nhé:
IteratorPatternDemo.java
public class IteratorPatternDemo { public static void main(String[] args) { NameRepository namesRepository = new NameRepository(); for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){ String name = (String)iter.next(); System.out.println("Name : " + name); } } }
Khi nào thì sử dụng Iterator Pattern?
Iterator là 1 pattern có định nghĩa và mục đích khá rõ ràng, vì vậy một trường hợp sử dụng hiển nhiên của pattern này là khi bạn cần truy cập phần tử của một tập hợp khi không biết rõ cấu trúc bên trong. Ngoài ra trong trường hợp ứng dụng sử dụng quá nhiều kiểu tập hợp, bạn cũng nên cân nhắc sử dụng pattern này.
Tham khảo
https://www.tutorialspoint.com/design_pattern/iterator_pattern.htm
https://gpcoder.com/4724-huong-dan-java-design-pattern-iterator/