迭代器模式(学习笔记)
1. 意图
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象内部表示
2. 动机
有时候,会使用不同的算法来遍历集合中的元素,不断地向集合中添加遍历算法会模糊其高效存储数据的主要职责。此外,有些算法可能是根据特定应用订制的,将其加入到泛型集合类中会显得非常奇怪。另一方面,使用多种集合的客户端代码可能并不关心存储数据的方式。不过,由于集合提供不同的元素访问方式,代码将不得不与特定的集合类耦合。迭代器模式的主要思想是将集合的遍历行为抽取为单独的迭代器对象。除实现自身算法外, 迭代器还封装了遍历操作的所有细节, 例如当前位置和末尾剩余元素的数量。 因此, 多个迭代器可以在相互独立的情况下同时访问集合。迭代器通常会提供一个获取集合元素的基本方法。 客户端可不断调用该方法直至它不返回任何内容, 这意味着迭代器已经遍历了所有元素。所有迭代器必须实现相同的接口。 这样一来, 只要有合适的迭代器, 客户端代码就能兼容任何类型的集合或遍历算法。 如果你需要采用特殊方式来遍历集合, 只需创建一个新的迭代器类即可, 无需对集合或客户端进行修改。
3. 适用性
- 访问一个聚合对象的内容而无须暴露它的内部表示
- 支持对聚合对象的多种遍历
- 为遍历不同的聚合结构提供一个统一的接口(即支持多态迭代)
4. 结构
5. 效果
1)单一职责原则。通过将体积庞大的遍历算法代码抽取为独立的类,可对客户端代码和集合进行整理
2) 开闭原则。 可以实现新型的集合和迭代器并将其传递给现有代码, 无需修改现有代码
3)可以并行遍历同一集合, 因为每个迭代器对象都包含其自身的遍历状态
4)如果你的程序只与简单的集合进行交互, 应用该模式可能会矫枉过正
6. 代码实现
iterators/ProfileIterator.java: 定义档案接口
package iterator.iterators; import iterator.profile.Profile; /** * @author GaoMing * @date 2021/7/19 - 19:24 */ public interface ProfileIterator { boolean hasNext(); Profile getNext(); void reset(); }
iterators/FacebookIterator.java: 在 Facebook 档案上实现迭代
package iterator.iterators; import iterator.profile.Profile; import iterator.social_networks.Facebook; import java.util.ArrayList; import java.util.List; /** * @author GaoMing * @date 2021/7/19 - 19:23 */ public class FacebookIterator implements ProfileIterator{ private Facebook facebook; private String type; private String email; private int currentPosition = 0; private List<String> emails = new ArrayList<>(); private List<Profile> profiles = new ArrayList<>(); public FacebookIterator(Facebook facebook, String type, String email) { this.facebook = facebook; this.type = type; this.email = email; } private void lazyLoad() { if (emails.size() == 0) { List<String> profiles = facebook.requestProfileFriendsFromFacebook(this.email, this.type); for (String profile : profiles) { this.emails.add(profile); this.profiles.add(null); } } } @Override public boolean hasNext() { lazyLoad(); return currentPosition < emails.size(); } @Override public Profile getNext() { if (!hasNext()) { return null; } String friendEmail = emails.get(currentPosition); Profile friendProfile = profiles.get(currentPosition); if (friendProfile == null) { friendProfile = facebook.requestProfileFromFacebook(friendEmail); profiles.set(currentPosition, friendProfile); } currentPosition++; return friendProfile; } @Override public void reset() { currentPosition = 0; } }
iterators/LinkedInIterator.java: 在领英档案上实现迭代
package iterator.iterators; import iterator.profile.Profile; import iterator.social_networks.LinkedIn; import java.util.ArrayList; import java.util.List; /** * @author GaoMing * @date 2021/7/19 - 19:24 */ public class LinkedInIterator implements ProfileIterator{ private LinkedIn linkedIn; private String type; private String email; private int currentPosition = 0; private List<String> emails = new ArrayList<>(); private List<Profile> contacts = new ArrayList<>(); public LinkedInIterator(LinkedIn linkedIn, String type, String email) { this.linkedIn = linkedIn; this.type = type; this.email = email; } private void lazyLoad() { if (emails.size() == 0) { List<String> profiles = linkedIn.requestRelatedContactsFromLinkedInAPI(this.email, this.type); for (String profile : profiles) { this.emails.add(profile); this.contacts.add(null); } } } @Override public boolean hasNext() { lazyLoad(); return currentPosition < emails.size(); } @Override public Profile getNext() { if (!hasNext()) { return null; } String friendEmail = emails.get(currentPosition); Profile friendContact = contacts.get(currentPosition); if (friendContact == null) { friendContact = linkedIn.requestContactInfoFromLinkedInAPI(friendEmail); contacts.set(currentPosition, friendContact); } currentPosition++; return friendContact; } @Override public void reset() { currentPosition = 0; } }
social_networks/SocialNetwork.java: 定义通用的社交网络接口
package iterator.social_networks; import iterator.iterators.ProfileIterator; /** * @author GaoMing * @date 2021/7/19 - 19:31 */ public interface SocialNetwork { ProfileIterator createFriendsIterator(String profileEmail); ProfileIterator createCoworkersIterator(String profileEmail); }
social_networks/Facebook.java: Facebook
package iterator.social_networks; import iterator.iterators.FacebookIterator; import iterator.iterators.ProfileIterator; import iterator.profile.Profile; import java.util.ArrayList; import java.util.List; /** * @author GaoMing * @date 2021/7/19 - 19:30 */ public class Facebook implements SocialNetwork{ private List<Profile> profiles; public Facebook(List<Profile> cache) { if (cache != null) { this.profiles = cache; } else { this.profiles = new ArrayList<>(); } } public Profile requestProfileFromFacebook(String profileEmail) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading profile '" + profileEmail + "' over the network..."); // ...and return test data. return findProfile(profileEmail); } public List<String> requestProfileFriendsFromFacebook(String profileEmail, String contactType) { // Here would be a POST request to one of the Facebook API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("Facebook: Loading '" + contactType + "' list of '" + profileEmail + "' over the network..."); // ...and return test data. Profile profile = findProfile(profileEmail); if (profile != null) { return profile.getContacts(contactType); } return null; } private Profile findProfile(String profileEmail) { for (Profile profile : profiles) { if (profile.getEmail().equals(profileEmail)) { return profile; } } return null; } private void simulateNetworkLatency() { try { Thread.sleep(2500); } catch (InterruptedException ex) { ex.printStackTrace(); } } @Override public ProfileIterator createFriendsIterator(String profileEmail) { return new FacebookIterator(this, "friends", profileEmail); } @Override public ProfileIterator createCoworkersIterator(String profileEmail) { return new FacebookIterator(this, "coworkers", profileEmail); } }
social_networks/LinkedIn.java: 领英
package iterator.social_networks; import iterator.iterators.LinkedInIterator; import iterator.iterators.ProfileIterator; import iterator.profile.Profile; import java.util.ArrayList; import java.util.List; /** * @author GaoMing * @date 2021/7/19 - 19:32 */ public class LinkedIn implements SocialNetwork{ private List<Profile> contacts; public LinkedIn(List<Profile> cache) { if (cache != null) { this.contacts = cache; } else { this.contacts = new ArrayList<>(); } } public Profile requestContactInfoFromLinkedInAPI(String profileEmail) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life... simulateNetworkLatency(); System.out.println("LinkedIn: Loading profile '" + profileEmail + "' over the network..."); // ...and return test data. return findContact(profileEmail); } public List<String> requestRelatedContactsFromLinkedInAPI(String profileEmail, String contactType) { // Here would be a POST request to one of the LinkedIn API endpoints. // Instead, we emulates long network connection, which you would expect // in the real life. simulateNetworkLatency(); System.out.println("LinkedIn: Loading '" + contactType + "' list of '" + profileEmail + "' over the network..."); // ...and return test data. Profile profile = findContact(profileEmail); if (profile != null) { return profile.getContacts(contactType); } return null; } private Profile findContact(String profileEmail) { for (Profile profile : contacts) { if (profile.getEmail().equals(profileEmail)) { return profile; } } return null; } private void simulateNetworkLatency() { try { Thread.sleep(2500); } catch (InterruptedException ex) { ex.printStackTrace(); } } @Override public ProfileIterator createFriendsIterator(String profileEmail) { return new LinkedInIterator(this, "friends", profileEmail); } @Override public ProfileIterator createCoworkersIterator(String profileEmail) { return new LinkedInIterator(this, "coworkers", profileEmail); } }
profile/Profile.java: 社交档案
package iterator.profile; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author GaoMing * @date 2021/7/19 - 19:25 */ public class Profile { private String name; private String email; private Map<String, List<String>> contacts = new HashMap<>(); public Profile(String email, String name, String... contacts) { this.email = email; this.name = name; // Parse contact list from a set of "friend:email@gmail.com" pairs. for (String contact : contacts) { String[] parts = contact.split(":"); String contactType = "friend", contactEmail; if (parts.length == 1) { contactEmail = parts[0]; } else { contactType = parts[0]; contactEmail = parts[1]; } if (!this.contacts.containsKey(contactType)) { this.contacts.put(contactType, new ArrayList<>()); } this.contacts.get(contactType).add(contactEmail); } } public String getEmail() { return email; } public String getName() { return name; } public List<String> getContacts(String contactType) { if (!this.contacts.containsKey(contactType)) { this.contacts.put(contactType, new ArrayList<>()); } return contacts.get(contactType); } }
spammer/SocialSpammer.java: 消息发送应用
package iterator.spammer; import iterator.iterators.ProfileIterator; import iterator.profile.Profile; import iterator.social_networks.SocialNetwork; /** * @author GaoMing * @date 2021/7/19 - 19:33 */ public class SocialSpammer { public SocialNetwork network; public ProfileIterator iterator; public SocialSpammer(SocialNetwork network) { this.network = network; } public void sendSpamToFriends(String profileEmail, String message) { System.out.println("\nIterating over friends...\n"); iterator = network.createFriendsIterator(profileEmail); while (iterator.hasNext()) { Profile profile = iterator.getNext(); sendMessage(profile.getEmail(), message); } } public void sendSpamToCoworkers(String profileEmail, String message) { System.out.println("\nIterating over coworkers...\n"); iterator = network.createCoworkersIterator(profileEmail); while (iterator.hasNext()) { Profile profile = iterator.getNext(); sendMessage(profile.getEmail(), message); } } public void sendMessage(String email, String message) { System.out.println("Sent message to: '" + email + "'. Message body: '" + message + "'"); } }
Demo.java: 客户端代码
package iterator; import iterator.profile.Profile; import iterator.social_networks.Facebook; import iterator.social_networks.LinkedIn; import iterator.social_networks.SocialNetwork; import iterator.spammer.SocialSpammer; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @author GaoMing * @date 2021/7/19 - 19:34 */ public class Demo { public static Scanner scanner = new Scanner(System.in); public static void main(String[] args) { System.out.println("Please specify social network to target spam tool (default:Facebook):"); System.out.println("1. Facebook"); System.out.println("2. LinkedIn"); String choice = scanner.nextLine(); SocialNetwork network; if (choice.equals("2")) { network = new LinkedIn(createTestProfiles()); } else { network = new Facebook(createTestProfiles()); } SocialSpammer spammer = new SocialSpammer(network); spammer.sendSpamToFriends("anna.smith@bing.com", "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?"); spammer.sendSpamToCoworkers("anna.smith@bing.com", "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link]."); } public static List<Profile> createTestProfiles() { List<Profile> data = new ArrayList<Profile>(); data.add(new Profile("anna.smith@bing.com", "Anna Smith", "friends:mad_max@ya.com", "friends:catwoman@yahoo.com", "coworkers:sam@amazon.com")); data.add(new Profile("mad_max@ya.com", "Maximilian", "friends:anna.smith@bing.com", "coworkers:sam@amazon.com")); data.add(new Profile("bill@microsoft.eu", "Billie", "coworkers:avanger@ukr.net")); data.add(new Profile("avanger@ukr.net", "John Day", "coworkers:bill@microsoft.eu")); data.add(new Profile("sam@amazon.com", "Sam Kitting", "coworkers:anna.smith@bing.com", "coworkers:mad_max@ya.com", "friends:catwoman@yahoo.com")); data.add(new Profile("catwoman@yahoo.com", "Liza", "friends:anna.smith@bing.com", "friends:sam@amazon.com")); return data; } }
执行结果
Please specify social network to target spam tool (default:Facebook): 1. Facebook 2. LinkedIn > 1 Iterating over friends... Facebook: Loading 'friends' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'mad_max@ya.com' over the network... Sent message to: 'mad_max@ya.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?' Facebook: Loading profile 'catwoman@yahoo.com' over the network... Sent message to: 'catwoman@yahoo.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?' Iterating over coworkers... Facebook: Loading 'coworkers' list of 'anna.smith@bing.com' over the network... Facebook: Loading profile 'sam@amazon.com' over the network... Sent message to: 'sam@amazon.com'. Message body: 'Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].'
7. 与其他模式的关系
- 可以使用迭代器模式来遍历组合模式树
- 可以同时使用工厂方法模式和迭代器来让子类集合返回不同类型的迭代器, 并使得迭代器与集合相匹配
- 可以同时使用备忘录模式和迭代器来获取当前迭代器的状态, 并且在需要的时候进行回滚
- 可以同时使用访问者模式和迭代器来遍历复杂数据结构,并对其中的元素执行所需操作,即使这些元素所属的类完全不同
8. 已知应用
- java.util.Iterator的所有实现 (还有 java.util.Scanner)
- java.util.Enumeration的所有实现
识别方法:迭代器可以通过导航方法(例如 next和 previous等)来轻松识别。使用迭代器的客户端代码可能没有其所遍历的集合的直接访问权限
原文地址:https://www.cnblogs.com/muxianbai/p/15031845.html
- 如何复制图文消息封面图片?正文没显示
- C#基础知识回顾--线程传参
- 数据库进程间通信解决方案IPC
- 苹果后端的Oracle数据库
- C#基础知识回顾--C#遍历enum类型、获取enum项个数
- 用香蕉也能玩电脑游戏—Tensorflow对象检测接口的简单应用
- 通过图片定位给一张图片添加多个链接
- Struts Interceptor Example
- 微信服务号模板消息接口新增"设置行业"和"添加模板"及细节优化
- WPF备忘录(3)如何从 Datagrid 中获得单元格的内容与 使用值转换器进行绑定数据的转换IValueConverter
- WPF备忘录(2)WPF获取和设置鼠标位置与progressbar的使用方法
- WPF文字修饰——上、中、下划线与基线
- 微信公众平台数据接口正式对所有认证公众号开放
- 参考基因组没有,经费也没那么多,怎么办?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android开发从相册中选取照片的示例代码
- 详解Android WebView的input上传照片的兼容问题
- Ubuntu14.04安装、配置与卸载QT5的步骤详解
- CentOS 8 安装 MariaDB的详细教程
- Android中RecyclerView拖拽、侧删功能的实现代码
- Android单个RecyclerView实现列表嵌套的效果
- Android如何禁止向EditText控件中输入内容详解
- 小程序视角下同构方案思考
- Android基于自带的DownloadManager实现下载功能示例
- Linux服务器搭建nvidia-docker环境过程详解
- Android开发中libs和jinLibs文件夹的作用详解
- Android多线程之同步锁的使用
- android.graphics.Matrix类用法分析
- 使用VSCode和SSH进行远程开发
- Android利用CountDownTimer实现倒计时功能 Android实现停留5s跳转到登录页面