迭代器模式(统一对集合的访问方式)

目录

前言

UML

plantuml

类图

实战代码

Iterator

ArrayList

Client

自定义迭代器

TreeNode

TreeUtils

Client


前言

在实际开发过程中,常用各种集合来存储业务数据并处理,比如使用 List,Map,Set 等等集合来存储业务数据。存储在集合中的数据,往往需要遍历集合元素再进行相应的业务处理。

不同的集合类型有不同的数据结构,遍历的方式也各不相同。

而迭代器模式,就是用来简化这项工作,让开发者不必关心底层的数据结构是如何组织的,只需关注如何取用数据。它解决了数据的获取与表示之间的耦合问题,提升了集合管理的灵活性与可维护性。

UML

plantuml

@startuml
'https://plantuml.com/class-diagram

interface Iterator {
    + hasNext() : boolean
    + next() : type
}

class ConcreteIterator {
    + hasNext() : boolean
    + next() : type
}

class Client {
    + iterator() : Iterator
}

Iterator <|.. ConcreteIterator

Client ..> Iterator

@enduml

类图

实战代码

Iterator

JDK 提供了 Iterator 这个顶级接口,JDK 下的集合都实现了 Iterator 接口,这样在遍历集合时,便可以直接使用 iterator 来遍历集合元素,而不用关心底层的数据结构。

ArrayList

以 ArrayList 为例,内部类 Itr 实现了 Iterator 接口,iterator 方法则实例化一个迭代器返回

Client

public class Client {  
    public static void main(String[] args) {  
        List<Integer> array = Arrays.asList(1, 2, 3, 4, 5);  
  
        Iterator<Integer> iterator = array .iterator();  
        while (iterator.hasNext()) {  
            System.out.println(iterator.next());  
        }  
    }  
}

自定义迭代器

如果 JDK 的集合类不满足业务需求,则需要自定义集合类,那么就需要自己实现 Iterator 接口,从而让自定义集合也能用统一的方式来遍历集合元素

以实际业务中最常见的分类树来举例,自定义 TreeNode 类,并实现 Iterator 接口

TreeNode

public class TreeNode {
    String id;
    String pid;
    String value;
    List<TreeNode> children;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public Iterator<TreeNode> iterator() {
        return new TreeNode.Itr(this);
    }

    private class Itr implements Iterator<TreeNode> {
        TreeNode currentNode;
        private Deque<TreeNode> stack;

        public Itr(TreeNode root) {
            currentNode = root;
            stack = new LinkedList<>();

            stack.push(root);
        }

        @Override
        public boolean hasNext() {
            return !stack.isEmpty();
        }

        @Override
        public TreeNode next() {
            if (!hasNext()) {
                throw new NoSuchElementException("No more elements to iterate.");
            }

            TreeNode node = stack.pop();
            currentNode = node;

            List<TreeNode> children = node.getChildren();
            if (children != null) {
                for (int index = children.size() - 1; index >= 0; index--) {
                    stack.push(children.get(index));
                }
            }

            return currentNode;
        }

    }
}

TreeUtils

public class TreeUtils {

    public final static String ROOT = "root";

    /**
     * 递归构造树
     *
     * @param sources 按parentId分类的节点
     * @param parentId 父id,根节点父id为null
     * @param getId 获取id
     * @param setChildren 设置子节点
     * @return 根节点集合
     * @param <T> 节点类
     * @param <R> id类型
     */
    public static <T, R> List<T> buildTree(Map<R, List<T>> sources, R parentId,
                                           Function<T, R> getId, BiConsumer<T, List<T>> setChildren) {
        List<T> nodes = sources.getOrDefault(parentId, emptyList());

        for (T node : nodes) {
            List<T> subNodes = buildTree(sources, getId.apply(node), getId, setChildren);
            setChildren.accept(node, subNodes);
        }

        return nodes;
    }

}

Client

public class Client {

    public static void main(String[] args) {
        TreeNode root = new TreeNode();
        root.setId("1");
        root.setPid(null);
        root.setValue("root");

        TreeNode child1 = new TreeNode();
        child1.setId("2");
        child1.setPid("1");
        child1.setValue("child1");

        TreeNode child2 = new TreeNode();
        child2.setId("3");
        child2.setPid("1");
        child2.setValue("child2");

        TreeNode child3 = new TreeNode();
        child3.setId("4");
        child3.setPid("2");
        child3.setValue("child3");

        //模拟从数据库中查到的节点数据
        List<TreeNode> nodes = Arrays.asList(root, child1, child2, child3);
        //按父节点分类
        Map<String, List<TreeNode>> sources = nodes.stream()
                .collect(groupingBy(e -> Objects.isNull(e.getPid()) ? ROOT : e.getPid()));
        //构造树
        List<TreeNode> tree = TreeUtils.buildTree(sources, ROOT, TreeNode::getId, TreeNode::setChildren);

        for (TreeNode node : tree) {
            Iterator iterator = node.iterator();
            while (iterator.hasNext()) {
                TreeNode child = (TreeNode) iterator.next();
                System.out.println(child.getId() + " " + child.getValue());
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值