欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

系统融合(二) -- 迭代器模式

程序员文章站 2022-05-04 14:41:40
...

聚合类型兼容性问题

 

接上一次分享《系统融合 -- 适配器模式》,在对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为了防止暴露内部数据结构,一般都采用内部迭代器。

 

 

 

  • 系统融合(二) -- 迭代器模式
            
    
    博客分类: 设计模式 迭代器模式 
  • 大小: 9.3 KB
相关标签: 迭代器模式