Android設計模式之——迭代器模式

一、介紹

迭代器模式(Iterator Pattern)又稱為游標(Cursor)模式,是行為型設計模式之一。迭代器模式算是一個比較古老的設計模式,其源于對容器的訪問,比如Java中的List、Map、數組等,我們知道對容器對象的訪問必然會涉及遍歷算法,我們可以將遍歷的方法封裝在容器中,或者不提供遍歷方法。如果我們將遍歷的方法封裝到容器中,那么對于容器類來說就承擔了過多的功能,容器類不僅要維護自身內部的數據元素而且還要對外提供遍歷的接口方法,因為遍歷狀態的存儲問題還不能對同一個容器同時進行多個遍歷操作,如果我們不提供遍歷方法而讓使用者自己去實現,又會讓容器的內部細節暴露無遺,正因于此,迭代模式應運而生,在客戶訪問類與容器體之間插入了一個第三者——迭代器,很好地解決了上面所述的弊端。

二、定義

提供一種方法順序訪問一個容器對象中的各個元素,而又不需要暴露該對象的內部表示。

三、使用場景

  • 遍歷一個容器對象。

四、迭代器模式的UML類圖

UML類圖:

這里寫圖片描述

通用模式代碼:

迭代器接口:

public interface Iterator<T> {/*** 是否還有下一個元素* @return true表示有,false表示沒有**/boolean hasNext();/*** 返回當前位置的元素并將位置移至下一位**/T next();
}

具體迭代器類:

public class ConcreteIterator<T> implements Iterator<T>{private List<T> list;private int cursor = 0;public ConcreteIterator(List<T> list) {this.list = list;}@Overridepublic boolean hasNext() {return cursor != list.size();}@Overridepublic T next() {T obj = null;if (this.hasNext()) {obj = this.list.get(cursor++);}return obj;}
}

容器接口:

public interface Aggregation<T> {/*** 添加一個元素**/void add(T obj);/*** 移除一個元素**/void remove(T obj);/*** 獲取容器的迭代器**/Iterator<T> iterator();
}

具體容器類:

public class ConcreteAggregation<T> implements Aggregation<T>{private List<T> list = new ArrayList<>();@Overridepublic void add(T obj) {list.add(obj);}@Overridepublic void remove(T obj) {list.remove(obj);}@Overridepublic Iterator<T> iterator() {return new ConcreteIterator<>(list);}
}

客戶類:

public class Client {public static void main(String args[]) {Aggregation<String> a = new ConcreteAggregation<>();a.add("a");a.add("b");a.add("c");Iterator<String> iterator = a.iterator();while (iterator.hasNext()) {System.out.print(iterator.next());}}
}

角色介紹:

  • Iterator:迭代器接口,迭代器接口負責定義、訪問和遍歷元素的接口。

  • ConcreteIterator:具體迭代器類,具體迭代器類的目的主要是實現迭代器接口,并記錄遍歷的當前位置。

  • Aggregate:容器接口,容器接口負責提供創建具體迭代器角色的接口。

  • ConcreteAggregate:具體容器類,具體迭代器角色與該容器相關聯。

  • Client:客戶類。

五、簡單實現

小民和小輝分別在公司的兩個事業部,某天老板安排任務讓他們倆統計一下各自部門的員工數據,這很好辦嘛,建一個類用數據結構把所有員工數據存進去即可,老板要看的時候給他用for循環實現,還是比較容易的,下面就先為員工創建一個實體類:

員工實體類:

public class Employee {private String name;// 姓名private int age;// 年齡private String sex;// 性別private String position;// 職位public Employee(String name, int age, String sex, String position) {super();this.name = name;this.age = age;this.sex = sex;this.position = position;}// 簡化代碼,省略setter和getter方法@Overridepublic String toString() {return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", sex="+ sex + ", position='" + position + '\'' + "}";}
}

小民部門:

public class CompanyMin {private List<Employee> list = new ArrayList<>();public CompanyMin(){list.add(new Employee("小民", 26, "男", "程序猿"));list.add(new Employee("小蕓", 22, "女", "測試"));list.add(new Employee("小方", 18, "女", "測試"));list.add(new Employee("可兒", 21, "女", "設計"));list.add(new Employee("朗情", 19, "女", "設計")); //吐槽一下,為什么就小民一個男的,小輝部門全男的。}public List<Employee> getEmployees(){return list;}
}

小輝部門:

public class CompanyHui {private Employee[] array = new Employee[3];public CompanyHui(){array[0] = new Employee("輝哥", 28, "男", "程序猿");array[1] = new Employee("小紅", 23, "男", "程序猿");array[2] = new Employee("小輝", 25, "男", "程序猿");}public Employee[] getEmployees(){return array;}
}

可見小民和小輝的內部實現是兩種方式,小民的人員信息容器的內部實質是使用的一個List類存儲人員信息,而小輝的實質上使用的是一個數組,如果老板要查看人員信息就必須遍歷兩個容器:

Boss查看:

public class Boss {public static void main(String[] args) {CompanyHui hui = new CompanyHui();Employee[] huiList = hui.getEmployees();for(int i = 0; i < huiList.length; i++){System.out.println(huiList[i]);}CompanyMin min = new CompanyMin();List minList = min.getEmployees();for(int i = 0; i < minList.size(); i++){System.out.println(minList.get(i).toString());}}
}

結果:

Employee{name='輝哥', age=28, sex=男, position='程序猿'}
Employee{name='小紅', age=23, sex=男, position='程序猿'}
Employee{name='小輝', age=25, sex=男, position='程序猿'}
Employee{name='小民', age=26, sex=男, position='程序猿'}
Employee{name='小蕓', age=22, sex=女, position='測試'}
Employee{name='小方', age=18, sex=女, position='測試'}
Employee{name='可兒', age=21, sex=女, position='設計'}
Employee{name='朗情', age=19, sex=女, position='設計'}

這樣看似也沒有問題,但是如果有多個部門,每個部門有各自的實現,那么我們就要在Boss類中增加一遍遍歷邏輯,這樣Boss類的功能會越來越多,同時暴露了內部細節。那么我們需要定義一個迭代器接口:

public interface Iterator {/*** 是否還有下一個元素 * * @return true表示有,false表示沒有*/boolean hasNext();/*** 返回當前元素,并將位置移至下一位*/Object next();
}

小民的迭代器:

public class MinIterator implements Iterator{private List<Employee> list;private int position;public MinIterator(List<Employee> list){this.list = list;}@Overridepublic boolean hasNext() {return !(position > list.size() - 1 || list.get(position) == null);}@Overridepublic Object next() {Employee e = list.get(position);position++;return e;}}

小輝的迭代器:

public class HuiIterator implements Iterator{private Employee[] array;private int position;public HuiIterator(Employee[] array){this.array = array;}@Overridepublic boolean hasNext() {return !(position > array.length - 1 || array[position] == null);}@Overridepublic Object next() {Employee e = array[position];position++;return e;}}

定義容器類的接口:

public interface Company {/*** 返回一個迭代器對象* * @return 迭代器對象*/Iterator iterator();}

修改一下之前的兩個容器類:

public class CompanyHui implements Company{private Employee[] array = new Employee[3];public CompanyHui(){array[0] = new Employee("輝哥", 28, "男", "程序猿");array[1] = new Employee("小紅", 23, "男", "程序猿");array[2] = new Employee("小輝", 25, "男", "程序猿");}public Employee[] getEmployees(){return array;}@Overridepublic Iterator iterator() {return new HuiIterator(array);}
}
public class CompanyMin implements Company{private List<Employee> list = new ArrayList<>();public CompanyMin(){list.add(new Employee("小民", 26, "男", "程序猿"));list.add(new Employee("小蕓", 22, "女", "測試"));list.add(new Employee("小方", 18, "女", "測試"));list.add(new Employee("可兒", 21, "女", "設計"));list.add(new Employee("朗情", 19, "女", "設計"));}public List<Employee> getEmployees(){return list;}@Overridepublic Iterator iterator() {return new MinIterator(list);}
}

Boss查看:

public class Boss {public static void main(String[] args) {CompanyHui hui = new CompanyHui();check(hui.iterator());CompanyMin min = new CompanyMin();check(min.iterator());}private static void check(Iterator iterator){while (iterator.hasNext()) {System.out.println(iterator.next().toString());}}
}

六、Android源碼中的迭代器模式

1、Cursor

當我們使用SQLiteDatabase的query方法查詢數據庫時,會返回一個Cursor游標對象,該游標的實質就是一個具體的迭代器,我們可以使用它來遍歷數據庫查詢所得的結果集。

七、總結

迭代器模式發展至今,幾乎所有的高級語言都有相應的內置實現,對于開發者而言,已經極少會自己去實現迭代器了,所以本章內容更多的是了解而非應用。

優點:

  • 符合面向對象設計原則中的單一職責原則。

  • 支持對容器對象的多種遍歷。弱化了容器類與遍歷算法之間的關系。

缺點:

  • 類文件的增加。

  • 會出現ConcurrentModificationException異常。

  • 遍歷過程是一個單向且不可逆的遍歷。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447006.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447006.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447006.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android設計模式之——模板方法模式

一、介紹 在面向對象開發過程中&#xff0c;通常會遇到這樣的一個問題&#xff0c;我們知道一個算法所需的關鍵步驟&#xff0c;并確定了這些步驟的執行順序&#xff0c;但是&#xff0c;某些步驟的具體實現是未知的&#xff0c;或者說某些步驟的實現是會隨著環境的變化而改變…

Android設計模式之——訪問者模式

一、介紹 訪問者模式是一種將數據操作與數據結構分離的設計模式&#xff0c;它是《設計模式》中23種設計模式中最復雜的一個&#xff0c;但它的使用頻率并不高&#xff0c;正如《設計模式》的作者GOF對訪問者模式的描述&#xff1a;大多數情況下&#xff0c;你不需要使用訪問者…

C++類模板template <class T>簡單使用方法

一個簡單的例子 兩個數比大小 如果兩個數都是int類型 class Compare_int { public :Compare(int a,int b){xa;yb;}int max( ){return (x>y)?x:y;}int min( ){return (x<y)?x:y;} private :int x,y; }; 如果兩個數是float類型 class Compare_float { public :Compare(…

Android設計模式之——中介者模式

一、介紹 中介者模式&#xff08;Mediator Pattern&#xff09;也稱為調解者模式或調停者模式&#xff0c;Mediator本身就有調停者和調解者的意思。 在日常生活中調停者或調解者這個角色我們見得比較多的是“和事老”&#xff0c;也就是說調解兩個有爭端的人的角色&#xff0…

C++智能指針中unique_ptr部分內容的講解

參考鏈接 std::unique_ptr 介紹 定義位于頭文件<memory>std::unique_ptr 是通過指針占有并管理另一對象&#xff0c;并在 unique_ptr 離開作用域時釋放該對象的智能指針。 在下列兩者之一發生時用關聯的刪除器釋放對象&#xff1a;1&#xff0c;銷毀了管理的 unique_pt…

Java基礎——Java多線程中sleep()、wait()和notify()

一、sleep()sleep()方法源碼&#xff1a;/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does …

Key_handle的學習

代碼 一切盡在不言中 #pragma once#include "common/common.h" #include "sdf/sdf.h"#include <memory>namespace sdf {namespace algorithm {class KeyHandle {public:using erased_internal_data_t char; //使用erased_internal_data_t等效于ch…

Java基礎——虛擬機結構

一、Java平臺結構圖二、JVM、JRE和JDK關系JVM&#xff1a;Java Virtual Machine&#xff08;Java虛擬機&#xff09;&#xff0c;負責執行符合規范的Class文件 JRE&#xff1a; Java Runtime Environment &#xff08;java運行環境&#xff09;&#xff0c;包含JVM和類庫 JDK&a…

解決 SSH Connection closed by foreign host 問題

用 Xshell 連接服務器總是報錯 : Connection closed by foreign host.Disconnected from remote host... 原因可能是 SSH 服務器沒設置保活時間間隔 , 具體設置如下 : 操作 # vim /etc/ssh/sshd_config 添加兩行 , 或去掉注釋 : ClientAliveInterval 60ClientAliveCountMax…

Java基礎——synchronized

synchronized重要&#xff01;重要&#xff01;重要&#xff01;重要的事情說三遍&#xff0c;一定要記下來哦。 Java語言的關鍵字&#xff0c;當它用來修飾一個方法或者一個代碼塊的時候&#xff0c;能夠保證在同一時刻最多只有一個線程執行該段代碼。一、當兩個并發線程訪問同…

C++:MAC安裝Boost庫文件并且使用CLion開發

boost的filestem庫 C在17版本的標準庫中引入了一個filesystem庫&#xff0c;用來處理文件路徑&#xff0c;以及文件訪問。很多編譯器對filesystem庫的支持還不是很好。為了解決這個問題&#xff0c;可以臨時使用boost::filesystem來替代。其實C17標準中的filesystem庫就是從bo…

Java基礎——Java異常處理機制

一、引言 try…catch…finally恐怕是大家再熟悉不過的語句了&#xff0c;而且感覺用起來也是很簡單&#xff0c;邏輯上似乎也是很容易理解。不過&#xff0c;我親自體驗的“教訓”告訴我&#xff0c;這個東西可不是想象中的那么簡單、聽話。不信&#xff1f;那你看看下面的代碼…

clion在使用sqlite3的時候,顯示Undefined symbols for architecture x86_64錯誤的解決辦法

顯示Undefined symbols for architecture x86_64錯誤的原因 1、缺少靜態庫 環境&#xff1a;在模擬器上報錯但在真機上能運行成功&#xff0c;而且報的錯誤來自于第三方庫。原因&#xff1a;architecture x86_64 是指模擬器的架構&#xff0c;意思就是 Crypto 變量在模擬器架…

Java基礎——Java反射機制及IoC原理

一、概念 主要是指程序可以訪問&#xff0c;檢測和修改它本身狀態或行為的一種能力&#xff0c;并能根據自身行為的狀態和結果&#xff0c;調整或修改應用所描述行為的狀態和相關的語義。在java中&#xff0c;只要給定類的名字&#xff0c; 那么就可以通過反射機制來獲得類的所…

Ubuntu boost庫文件安裝編譯

簡單介紹 Boost庫是為C語言標準庫提供擴展的一些C程序庫的總稱&#xff0c;由Boost社區組織開發、維護.Boost向來有準標準庫之稱&#xff0c;很多新特性例如智能指針等都是先在boost中實現&#xff0c;后來被吸收到標準庫之中. Boost實現了日志、算法、日期、地理、數學、線程…

Java基礎——類加載機制及原理

一、什么是類的加載&#xff1f; 類的加載指的是將類的.class文件中的二進制數據讀入到內存中&#xff0c;將其放在運行時數據區的方法區內&#xff0c;然后在堆區創建一個java.lang.Class對象&#xff0c;用來封裝類在方法區內的數據結構。類的加載的最終產品是位于堆區中的Cl…

在Ubuntu環境下使用vcpkg安裝sqlite_orm包文件

Ubuntu安裝vcpkg 從github下載vcpkg的安裝包&#xff0c;在usr/local路徑下面執行如下命令 git clone https://github.com/Microsoft/vcpkg.git cd vcpkg //進入源碼目錄 ./bootstrap-vcpkg.sh //執行./bootstrap-vcpkg.sh進行編譯安裝&#xff0c;這個過程很慢 編譯安裝好…

finally語句與return語句的執行順序

網上有很多人探討Java中異常捕獲機制try...catch...finally塊中的finally語句是不是一定會被執行&#xff1f;很多人都說不是&#xff0c;當然他們的回答是正確的&#xff0c;經過我試驗&#xff0c;至少有兩種情況下finally語句是不會被執行的&#xff1a; try語句沒有被執行到…

window電腦查看ssh公鑰,以及將自己的公鑰添加到Github等類似網站

查看本機的ssh公鑰 使用命令 cd ~/.ssh使用命令 ls 可以看到 id_rsa id_rsa.pub known_hosts 三個文件&#xff0c;此處需要的是id_rsa.pub文件使用命令 cat id_rsa.pub 查看文件的內容拷貝這段內容 添加自己的公鑰 進入賬戶的設置頁面參照如下步驟&#xff0c;進入SSH Key…

java八大排序算法

一、概述 排序有內部排序和外部排序&#xff0c;內部排序是數據記錄在內存中進行排序&#xff0c;而外部排序是因排序的數據很大&#xff0c;一次不能容納全部的排序記錄&#xff0c;在排序過程中需要訪問外存。 我們這里說說八大排序就是內部排序。 當n較大&#xff0c;則應采…