聚合类型兼容性问题
接上一次分享《系统融合 -- 适配器模式》,在对A、B两个系统进行融合的过程中,可以使用“适配器模式”把两类业务类似但接口定义不同的接口适配为同一个系统。在两个系统融合过程中,还经常遇到另一种情况:A系统返回的商品列表是ArrayList类型,B系统返回的商品列表是数组类型。
//A系统获取商品列表接口 public List<Product> getProdoucts(){ //省略业务代码 } //B系统获取商品列表接口 public Product [] getProdoucts(){ //省略业务代码 }
这就是所谓的“聚合类型兼容性问题”。这时为了统一接口类型,可以在“适配器系统”把ArrayList转换成数组,或者把数组转换成ArrayList。但这不是最优雅的方式,我们还可以使用“迭代器模式”对两个接口进行兼容。Java中得聚合类型:数组、List、Set、Map等。
在使用“迭代器模式”解决这个兼容性问题之前,首先来看看什么是“迭代器模式”。
迭代器模式
迭代器模式提供一种顺序访问一个聚合对象中的各个元素的方法,而又不暴露其内部的表象。把遍历聚合中各个元素的任务移交到“迭代器”上,满足OO设计原则中的“单一责任原则”。另外具体的“迭代器”都实现自一个统一的接口(Iterator),可以兼容不同的聚合类型遍历(这就是解决本文开头“兼容性”问题的关键)。
简单的理解,就是把聚合类型中遍历每个成员的任务剥离出来,生成“迭代器”,这些迭代器都实现自同一个接口。类图关系:
从类图上看,该模式主要有4类角色:
抽象的聚合:AbsAggregate,可以是抽象类 也可以是接口。一般都会定义一个抽象方法,获取迭代器。
具体的聚合:ConcreteAggregate,实现或继承自AbsAggregate。一般都会实现AbsAggregate中的抽象方法,获取具体的迭代器。
抽象的迭代器:Iterator可以是抽象类 也可以是接口。一般最少有两个抽象方法,hasNext()和next()方法,用于遍历聚合中的元素。
具体的迭代器:ConcreteIterator,实现或继承自Iterator。对hasNext()和next()方法进行具体的实现。其构造过程依赖“具体的聚合”,也就是说每个“具体的聚合”,一般都会对应一个自己 “具体的迭代器”。
示例展示
回到文章开头,开始使用“迭代器模式”对A、B两个系统融合过程中,对两个不同的获取商品列表接口进行融合。为了方便理解,实现过程按照“迭代器模式”的4类角色 分类进行:
抽象的聚合:本示例中抽象的聚合是ProdcutAdapter接口,里面只定义了一个createIterator()的抽象方法:
public interface ProdcutAdapter { //批量获取商品接口 Iterator<Product> createIterator(); }
具体的聚合:本示例中有两个系统进行融合,对应有两个具体的聚合:ProdcutAdapterAImpl(对应List类型的商品列表接口)、ProdcutAdapterBImpl(对应数组类型的商品接口)。核心是对createIterator方法的实现:
public class ProdcutAdapterAImpl implements ProdcutAdapter { public Iterator<Product> createIterator() { List<Product> products =getProdoucts(); Iterator iterator = new ListIterator(products); return iterator; } //模拟从A系统获取List类型的商品列表 public List<Product> getProdoucts(){ //省略调用A系统方法,获取数组类型的商品列表 Product p1 = new Product(); p1.setId(1000); p1.setName("A系统1000商品"); Product p2 = new Product(); p2.setId(1001); p2.setName("A系统1001商品"); List<Product> products = new ArrayList(); products.add(p1); products.add(p2); return products; } } public class ProdcutAdapterBImpl implements ProdcutAdapter { public Iterator<Product> createIterator() { Product [] array = getProdoucts(); Iterator iterator = new ArrayIterator(array); return iterator; } //模拟从B系统获取数组类型的商品列表 public Product [] getProdoucts(){ //省略调用B系统方法,获取数组类型的商品列表 Product p3 = new Product(); p3.setId(1003); p3.setName("B系统1003商品"); Product p4 = new Product(); p4.setId(1004); p4.setName("B系统1004商品"); Product [] array = {p3,p4}; return array; } }
抽象的迭代器:Iterator,这里只定义迭代器的两个核心方法 hasNext和next:
public interface Iterator<E> { boolean hasNext(); Object next(); }
具体的迭代器:本示例中有两类聚合,List和数组。对应的会创建两个具体的迭代器:ListIterator、ArrayIterator
public class ListIterator<E> implements Iterator{ private List<E> products; int pos=0;//当前位置 //外部迭代器,构造函数需要传入一个待迭代的集合类型 public ListIterator(List<E> products) { this.products = products; } public boolean hasNext() { if (pos >= products.size()) { return false; } else { return true; } } public Object next() { E product = products.get(pos); pos = pos + 1; return product; } } public class ArrayIterator<E> implements Iterator{ private E [] products; int pos=0;//当前位置 //外部迭代器,构造函数需要传入一个待迭代的集合类型 public ArrayIterator(E[] products) { this.products = products; } public boolean hasNext() { if (pos >= products.length) { return false; } else { return true; } } public Object next() { E product = products[pos]; pos = pos + 1; return product; } }
到这里“迭代器模式”的4类角色的实现完成,下面开始测试:
public class Main { public static void main(String[] args) { ProdcutAdapter prodcutAdapterA = new ProdcutAdapterAImpl(); ProdcutAdapter prodcutAdapterB = new ProdcutAdapterBImpl(); //获取迭代器,两个老系统接口被统一为一个迭代器类型 Iterator iteratorA = prodcutAdapterA.createIterator(); Iterator iteratorB = prodcutAdapterB.createIterator(); //展示商品列表 showProducts(iteratorA); showProducts(iteratorB); } //模拟商品列表展示 public static void showProducts(Iterator iterator){ while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println(" "); } }
执行main方法,打印结果为:
Product{id=1000, name='A系统1000商品', category='null', venderId=null} Product{id=1001, name='A系统1001商品', category='null', venderId=null} Product{id=1003, name='B系统1003商品', category='null', venderId=null} Product{id=1004, name='B系统1004商品', category='null', venderId=null}
这里main方法是展示的如何让“客户端”无感知的调用A、B两个系统的获取商品列表方法,并采用统一的方法进行打印。换句话说“客户端”无需关心商品列表是List类型 还是 数组类型。
到这里,使用“迭代器模式”已经优雅的解决是两个系统“融合”过程中,聚合类型不兼容的问题。
Java中的迭代器
Java的API中对大部分的聚合类型都已经默认实现了自己的迭代器,统一实现自接口java.util.Iterator,相比本示例中定义的Iterator,java.util.Iterator多了一个remove方法:
public interface Iterator<E> { boolean hasNext(); E next(); default void remove() }
在上述示例中,我们自己实现了ArrayList类型的迭代器ArrayIterator,这里仅仅为了做示例演示使用。其实java API中ArrayList,已经有自己的迭代器实现,直接调用其iterator()方法即可。
如果本示例改用java.util.Iterator作为抽象的迭代器,ArrayIterator几乎不用改,去掉ArrayIterator实现,在ProdcutAdapterAImpl中把:
Iterator iterator = new ListIterator(products);
改为:
Iterator iterator = products.iterator();
Java api中几乎已为所有的聚合类型创建了自己的迭代器,并且都实现自java.util.Iterator接口。如果要扩展自定义聚合类型的迭代器,直接实现这个接口即可,这样做的好处是可以跟java api中的聚合类型的迭代器完全兼容。
内、外部迭代器
最后再提下内部迭代器和外部迭代器,本次示例中使用独立的类创建具体的迭代器,这属于外部迭代器。Java API中的实现都是内部迭代器:迭代器实现类做为聚合的一个内部类。这两种方式有各自的优缺点:
外部迭代器:优点 “单一责任原则”更彻底,具备更好的复用性。缺点 暴露聚合的内部成员。创建迭代器时,需要具体的聚合类型作为参数:
Iterator iterator = new ListIterator(products);
内部迭代器:优缺点刚好与外部迭代器相反。创建迭代器时,不需要参数:
Iterator iterator = products.iterator();
Java API为了防止暴露内部数据结构,一般都采用内部迭代器。
相关推荐
《激光原理课程设计--平行平面腔自再现模Fox-Li数值迭代解法及MATLAB实现》 ...通过这个设计,学生可以深入探索激光器的工作机制,进一步理解光的衍射和波动性质,以及如何利用这些原理来设计和分析激光系统。
- 迭代器模式:提供一种方法顺序访问聚合对象的元素,而不暴露其底层表示。 - 中介者模式:定义一个中介对象来简化原本复杂的对象之间的交互。 - 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,...
- **迭代式开发**:说明了测试如何促进迭代式开发的有效实施。 - **持续集成**:分析了测试在持续集成过程中的作用。 - **重构**:讨论了测试对于重构过程的影响。 - **测试先行的应用开发**: - **测试框架**:...
综上所述,FingYou_V3.5项目似乎是一个基于数据融合和D-S证据理论的识别系统,利用迭代自组织数据分析进行模板训练,以提高对复杂或模糊信息的识别性能。压缩包中的"fingyou_V3.5.m"文件很可能包含了该系统的源代码...
设计模式之 Iterator(迭代器) 这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入Collection中, 直接使用 Iterator 进行对象遍历。 设计模式之 Template(模板方法) ...
2. 智能化设计:通过手机APP或车载系统,用户可实时查看车内空气质量,远程控制设备开关,甚至根据环境自动调节工作模式。 3. 用户体验:注重产品外观设计,使之与车内装饰风格相融合,同时考虑低噪音运行,提升...
16. **迭代器模式**(Iterator Pattern):提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 17. **访问者模式**(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变...
- 块(block)与迭代器(iterator)的作用及应用场景。 - 文件读写操作的基本方法。 - **进阶话题** - 单元测试框架的使用。 - 调试技巧与错误处理。 #### 二、Ruby与环境的深度融合 - **解释器选项详解** - ...
模式识别通常更注重从工程应用的角度出发,目标是建立有效的分类系统,而机器学习则更偏向于理论研究,关注如何通过学习来改善系统的性能,如泛化能力和算法的收敛性。 在模式识别中,常用的算法包括K近邻(KNN)...
6. **目录树遍历迭代器**:在Scala中,通过迭代器遍历目录树可以高效地处理文件系统的递归任务,如查找特定文件、递归删除或复制目录结构等,这对于处理大量文件或深度嵌套的目录结构非常有用。 这些知识对于学习和...
13. **迭代器模式**:提供一种方法顺序访问聚合对象的元素,而又不暴露其底层表示。 14. **命令模式**:将请求封装为一个对象,使得你可以用不同的请求参数化其他对象,也支持可撤销操作。 15. **责任链模式**:...
迭代算法ARTII程序是一种在信号处理领域广泛应用的自动相关矩阵(ART)算法的变体,主要设计用于模式识别和学习任务。ARTII是基于自适应神经网络的算法,它能够在线性不可分的数据集上进行分类,尤其适用于处理高维...
结构型模式(如适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式)和行为型模式(如策略模式、模板方法模式、命令模式、迭代器模式、访问者模式、责任链模式、备忘录模式、观察者模式、状态...
- 2020-2021年中国避雷器行业的发展情况和未来发展趋势,特别提到了能源互联网背景下输配电设备行业的新业态和新技术迭代。 - 我国避雷器行业的竞争格局以及主要企业的经营情况和研发投入。 - 金冠电气的案例分析,...
- **使用迭代器**:讲解了如何有效地使用迭代器进行数据处理。 #### 十四、惰性值 这一部分介绍了Scala中的惰性计算特性,包括惰性值的概念及其应用场景。 #### 十五、隐式参数与转换 这部分内容涉及Scala中隐式...
4. **行为型模式**:如策略模式(Strategy)、命令模式(Command)、观察者模式(Observer)、模板方法模式(Template Method)、迭代器模式(Iterator)、访问者模式(Visitor)、备忘录模式(Memento)、状态模式...
《推荐系统在亚马逊数据集中的应用——以"amazon-boys and girls"为例》 推荐系统是现代电商领域中不可或缺的一部分,它通过分析用户的行为、兴趣和偏好,为用户提供个性化的产品或服务建议。在这个主题中,我们将...
Firefox火狐浏览器是一款深受用户喜爱的开源网络浏览器,其官方45.0.1-mac版本专为Mac OS操作系统设计。这款浏览器以其强大的安全性、高度的定制化和对Web标准的出色支持而闻名。在Mac平台上,Firefox 45.0.1提供了...
行为型模式则包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。例如,观察者模式定义了对象间的一种一对多的依赖关系,当一...