【一起学系列】之迭代器&组合:虽然有点用不上啦
2020/6/15 17:26:12
本文主要是介绍【一起学系列】之迭代器&组合:虽然有点用不上啦,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
迭代器模式
意图
提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴漏该对象的内部表示
迭代器模式的诞生
【产品】:嘿,有一个好消息,咱们旗下的餐厅把月巴克的咖啡店吞并了!太棒了!年终奖稳了!
【开发】:Yeah!Yeah!Yeah!
【产品】:但是他们好像反应一个问题,月巴克的点餐系统好像不兼容我们的体系,怎么回事?不就是一个菜单吗?
【开发】:Oh!No!一定它们的 数据结构 不一样导致的,遍历出现了问题!
【产品】:那怎么办?BOSS,你们一起想想办法吧!
【开发】:老大,我们能不能把遍历方法抽取出来啊?我们遍历操作就可以不用考虑各种细节了,只需要管遍历类就好了。
【BOSS】:什么遍历类的,这叫 迭代器 好吗!其实JDK对于迭代器已经维护的很好了,但是咱们这业务也有一点特殊性,就按你说的办吧,办不好的话,刚才说的年终奖就没了。
【开发】:哦,好的(脸上笑嘻嘻,心里MMP)
HeadFirst 核心代码
自己整一个迭代器
「定义迭代器持有者 非必须代码」
/** * ****************************** * description: 迭代器持有者 * ****************************** */ public interface MyContainer { MyIterator getIterator(); } 复制代码
「迭代器接口」
/** * ****************************** * description: 迭代器接口 * ****************************** */ public interface MyIterator { boolean hasNext(); Object next(); } 复制代码
「迭代器工作类 食物菜单」
public class FoodRepository implements MyContainer { String[] names = {"宫保鸡丁", "麻辣香锅", "油闷大虾"}; @Override public MyIterator getIterator() { return new NameIterator(); } private class NameIterator implements MyIterator { private int index; @Override public boolean hasNext() { return index < names.length; } @Override public Object next() { return hasNext() ? names[index++] : null; } NameIterator() { index = 0; } } } 复制代码
「迭代器工作类 咖啡菜单」
public class CoffeeRepository implements MyContainer { List<String> names = Arrays.asList("雀巢咖啡", "黑糖玛奇朵", "半点寂寞"); @Override public MyIterator getIterator() { return new NameIterator(); } private class NameIterator implements MyIterator { private int index; @Override public boolean hasNext() { return index < names.size(); } @Override public Object next() { return hasNext() ? names.get(index++) : null; } NameIterator() { index = 0; } } } 复制代码
「测试类 观察调用的表现形式」
public class App { public static void main(String[] args){ // 餐厅菜单 FoodRepository food = new FoodRepository(); MyIterator foodIterator = food.getIterator(); while (foodIterator.hasNext()) { System.out.println("Food: -> " + foodIterator.next()); } CodeUtils.spilt(); // 咖啡菜单 CoffeeRepository coffee = new CoffeeRepository(); MyIterator coffeeIterator = coffee.getIterator(); while (coffeeIterator.hasNext()) { System.out.println("Coffee: -> " + coffeeIterator.next()); } } } 复制代码
JDK中的迭代
public class App { public static void main(String[] args){ // JDK List<String> names = Arrays.asList("Han", "John", "Tomams"); Iterator<String> iterable = names.iterator(); while (iterable.hasNext()) { System.out.println("JDK Iterator: -> " + iterable.next()); } CodeUtils.spilt(); // JDK names.forEach(s -> System.out.println("JDK forEach: -> " + s)); } } 复制代码
因此对于业务上没有什么要求且常见的数据结构,我们不再需要自行定义迭代器
迭代器模式的设计思路:
Iterator 迭代器 Concretelterator 具体迭代器 Aggregate 集合 ConcreteAggregate 具体集合
简单来说,
我们需要明确集合的类型(数组,链表,Map,树结构或者普通List) 我们需要定义迭代器的行为,是否有下一个(遍历完成),取值,移除等等 遍历的行为或者算法在具体的迭代器中实现,根据不同的数据结构和业务要求完成编码,实现访问一致,但细节不同的效果
❝如果看着有点模棱两可,就看完本文后,访问专题设计模式开源项目,里面有具体的代码示例,链接在最下面
❞
遵循的设计原则
单一职责原则
说明:迭代器类在设计中仅仅包含集合迭代的作用,它是把原本数据结构中的遍历抽取出来,达到 高内聚 的效果。
所谓高内聚:当一个模块或一个类被设计成只支持一组相关功能时,我们说它具有 高内聚 的特征。
什么场景适合使用
访问一个聚合对象的内容而无需暴漏它的内部表示 支持对聚合对象的多种遍历 为遍历不同的聚合结构提供一个统一的接口
Code/生活中的实际应用
举一个不是很恰当的例子,我们都用自动贩卖机买过水,付钱之后它会自动滚出来,大家有没有想过它是怎么实现这个效果的呢?它支持瓶装的,罐装的,甚至还支持袋装的,方便面,口红等等五花八门的产品,它的内部结构可能都各不相同,但是最终的表现效果就是我们直接从出口处拿即可,这是不是迭代器模式的一种体现呢?
迭代器模式UML图
组合模式
意图
将对象组合成树形结构以表示 “部分-整体” 的层次结构,Composite使得用户对单个对象和组合对象的使用具有一致性
说人话:想想Java里的File类
组合模式的误区
组合模式 不是 一堆模式的组合!
组合模式的诞生
【开发】:老大,我在写菜单类的时候感觉好痛苦啊!
【BOSS】:怎么了?
【开发】:菜单有真正的菜品,还有父级菜单啊,它们俩得维护两套逻辑,混在一起好难受!
【BOSS】:你在操作文件的时候怎么不觉得难受?你咋不动动脑子想着抽象一下啊!
【开发】:对啊!我去改代码!
HeadFirst 核心代码
「定义抽象行为」
/** * ****************************** * description: 定义抽象行为 * ****************************** */ public abstract class MenuComponent { public String name; /*** * 添加 */ public abstract void add(MenuComponent component) throws Exception; /*** * 移除 */ public abstract void remove(MenuComponent component) throws Exception; /*** * 获取菜单名 */ public abstract String getName(); /*** * 获取子菜单 */ public abstract MenuComponent getChild(int i) throws Exception; /*** * 打印菜单 */ public abstract void print(); } 复制代码
「实现 “整体”」
public class Menu extends MenuComponent{ List<MenuComponent> menuComponents = new ArrayList<>(); public Menu(String name) { this.name = name; } @Override public void add(MenuComponent component) { this.menuComponents.add(component); } @Override public void remove(MenuComponent component) { this.menuComponents.remove(component); } @Override public String getName() { return this.name; } @Override public MenuComponent getChild(int i) { return menuComponents.get(i); } @Override public void print() { System.out.println("当前菜单项: " + getName()); for (MenuComponent component : menuComponents) { component.print(); } } } 复制代码
「实现 "部分"」
public class MentItem extends MenuComponent{ public MentItem(String name) { this.name = name; } @Override public void add(MenuComponent component) throws Exception { throw new Exception("无法添加"); } @Override public void remove(MenuComponent component) throws Exception { throw new Exception("无法移除"); } @Override public String getName() { return this.name; } @Override public MenuComponent getChild(int i) throws Exception { throw new Exception("无子节点"); } @Override public void print() { System.out.println(" 食物名: " + getName()); } } 复制代码
「测试类」
public class App { /*** * 推荐代码阅读顺序: * * @see MenuComponent * @see Menu * @see MentItem */ public static void main(String[] args) { Menu meat = new Menu("炒菜类"); MentItem item1 = new MentItem("宫保鸡丁"); MentItem item2 = new MentItem("剁椒鸡蛋"); MentItem item3 = new MentItem("鱼香肉丝"); Menu vegetable = new Menu("素食"); MentItem v1 = new MentItem("酸辣土豆丝"); MentItem v2 = new MentItem("爆炒包菜"); meat.add(item1); meat.add(item2); meat.add(item3); vegetable.add(v1); vegetable.add(v2); meat.add(vegetable); meat.print(); } } /*** * 输出内容: * * 当前菜单项: 炒菜类 * 食物名: 宫保鸡丁 * 食物名: 剁椒鸡蛋 * 食物名: 鱼香肉丝 * 当前菜单项: 素食 * 食物名: 酸辣土豆丝 * 食物名: 爆炒包菜 */ 复制代码
组合模式的设计思路:
Component 为组合的对象声明接口或抽象类 Leaf 叶子节点(最小单元) Composite 组合节点(即还有子节点的节点) Client 客户端,调用方
简单来说,
当我们需要树形结构时,抽象叶子节点和组合节点(有子节点的节点)的共同行为 让两者实现同一个接口
❝如果看着有点模棱两可,就看完本文后,访问专题设计模式开源项目,里面有具体的代码示例,链接在最下面
❞
什么场景适合使用
需要表示对象的部分-整体层次结构 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中所有对象
Code/生活中的实际应用
依然是一个不太恰当的例子,我们在操作文件和文件夹的时候,都有其移动,复制,重命名,查看文件大小等等功能,对于Java来说,它的底层实现是有一个 是否是文件夹
的方法来区分,但实际上这也是组合模式的根本思想,即对于表示 部分 的对象,和 整体 的对象,拥有统一的操作行为
组合模式的UML图
总结
迭代器模式:该模式在JDK中已经封装的非常好,我们其实不太需要再自行处理,不过在处理特殊数据结构时这种统一操作的思想仍然值得借鉴 组合模式:组合模式仅在需要树形结构的场景下可发挥巨大的作用,同样的,它规范不同类型对象的行为,统一操作的思想,值得我们借鉴
相关代码链接
GitHub地址
兼顾了《HeadFirst》以及《GOF》两本经典书籍中的案例 提供了友好的阅读指导
本文使用 mdnice 排版
这篇关于【一起学系列】之迭代器&组合:虽然有点用不上啦的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求