• 设计模式迭代器


    设计模式学习核心与要领:

    1.每个模式长什么样子?

    2.如果不用这个模式 会有什么问题,如果用了这个模式 会有什么好处?

    3.一般在企业开发中,这个模式是怎么用的?即在实际的企业开发场景里面,是如何应用的?

    最重要的是(要在项目里去实践),在一个项目中,比如电商系统里,将所有这些设计模式,全部在真实复杂的电商业务中去深入的使用,结合业务来设计这个模式如何运用到业务中,基于设计模式 开发出 高内聚、低耦合、高度可扩展、维护成本低、逻辑清晰、易读易懂的代码。

    面试技巧:考察 设计模式的运用和实践功底。

    首先,结合自己做过的复杂业务系统,给人家先讲一讲业务;

    然后,说一下 如果不用这个模式来设计这个业务的代码实现,可能会导致代码 会有什么问题;

    然后,但是你当时合理的运用了设计模式(不能生搬硬套,导致为了用模式而用模式),将代码设计的结构如何优良,可扩展性如何的好,维护性如何的好。

    迭代器模式:本质就是面向接口编程

    需求:迭代教室里的学生,设计一个Classroom类 和 Student类。

    为了方便调用和演示,把他们都写成一个类里的静态内部类的形式(如果写在类的外面,就不能添加static);

    Student类只有一个String属性name,Classroom只有一个Student数组属性students,并分别生成有参构造器,get/set方法 和 toString方法;

    然后,写一个main方法,new出两个学生,student1小灵儿和student2小帆儿,并添加到Student[2]数组students中,

    然后,再new出 一个Classroom,将students数组set到Classroom中

    最后,再从Classroom中获取到学生数组,进行遍历。

    那么这时,出于一定的原因,我不想用数组来储存Classroom中的Student学生了,我用Map来储存Map<String, Student>,那么关于使用Classroom有关的代码(将学生set到Classroom和对Classroom进行迭代),就都要随之改动。即牵一发而动全身。

    小结:如果不用任何设计模式,直接去遍历一个类中的集合,一旦这个类中对集合的使用改变了,比如从数组到map或List等,那么你迭代的这块代码,就要改动。

    如果说代码和业务逻辑很复杂,同时集合类的实现和遍历代码的实现,是两个人开发的,这个成本就很高了,因为代码报错了,大家又要协调,然后又要改动。

    简单来说,这种代码的可扩展性,可维护性都很差,因为不好扩展,一扩展就要改代码,不好维护。

    public class NonPatternApplication {
    
        public static void main(String[] args) {
            Student student1 = new Student("小灵儿");
            Student student2 = new Student("小帆儿");
    
    //        Student[] students = new Student[2];
    //        students[0] = student1;
    //        students[1] = student2;
            Map<String, Student> students = new HashMap<String, Student>();
            students.put(student1.name, student1);
            students.put(student2.name, student2);
    
            Classroom classroom = new Classroom();
            classroom.setStudents(students);
    
    //        Student[] resultStudents = classroom.getStudents();
    //        for (Student resultStudent : resultStudents) {
    //            System.out.println(resultStudent);
    //        }
            Map<String, Student> resultStudents = classroom.getStudents();
            for (Student resultStudent : resultStudents.values()) {
                System.out.println(resultStudent);
            }
        }
    
        public static class Student{
            public Student(String name) {
                this.name = name;
            }
    
            private String name;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        /*public static class Classroom {
    
            private Student[] students;
    
            public Student[] getStudents() {
                return students;
            }
    
            public void setStudents(Student[] students) {
                this.students = students;
            }
        }*/
    
        public static class Classroom {
    
            private Map<String, Student> students;
    
            public Map<String, Student> getStudents() {
                return students;
            }
    
            public void setStudents(Map<String, Student> students) {
                this.students = students;
            }
        }
    }

     下面通过迭代器模式实现开发如下:

    public class PatternApplication {
    
        public static void main(String[] args) {
            Student student1 = new Student("小灵儿");
            Student student2 = new Student("小帆儿");
    
            Classroom classroom = new Classroom(2);
            classroom.addStudent(student1);
            classroom.addStudent(student2);
    
            // 这里我们遍历教室里的学生,先是拿到教室的这个迭代器,
            // 然后面向迭代器这个接口提供的hasNext()和next()方法,去做的遍历开发
            Iterator iterator = classroom.iterator();
            while (iterator.hasNext()) {
                Student student = (Student) iterator.next();
                System.out.println(student);
            }
    
        }
        /**定义一个我们自己的迭代器接口*/
        public interface Iterator {
            // 集合是否有下一个元素
            public abstract boolean hasNext();
            // 获取这个集合的下一个元素
            public abstract Object next();
        }
        /**代表了一个集合类*/
        public interface Aggregate {
            // 此方法可以返回这个集合对应的一个迭代器
            public abstract Iterator iterator();
        }
    
        /**学生类*/
        public static class Student{
            public Student(String name) {
                this.name = name;
            }
    
            private String name;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        /**
         * 教室迭代器(含有Classroom的引用)
         * 负责两件事:1.数据集合它有没有下一个元素;2.获取数据集合当前的这个元素
         */
        public static class ClassroomIterator implements Iterator{
            // 因为含有Classroom的引用,就可以从Classroom里面,拿到它对应的数据集合
            private Classroom classroom;
            private int index;
    
            public ClassroomIterator(Classroom classroom) {
                this.classroom = classroom;
                // 刚开始初始的index是0
                this.index = 0;
            }
    
            // 判断 Classroom 里面是否含有下一个学生,
            // 如果index小于Classroom中数据集合的长度,才能够获取下一个元素,就是说数组还没有遍历完成
            // 假设此时index是2,classroom的length是2,classroom可以遍历的数组的offset只能是0和1
            @Override
            public boolean hasNext() {
                if (index < classroom.getLength()) {
                    return true;
                } else {
                    return false;
                }
            }
    
            // 从数组中获取当前的学生,同时将index往下移动一位
            @Override
            public Object next() {
                Student student = classroom.getStudent(index);
                index++;
                return student;
            }
        }
        /**教室类*/
        public static class Classroom implements Aggregate{
    
            private Student[] students;
            // last相当于数据的长度(数组指针)
            private int last = 0;
    
            public Classroom(int size) {
                this.students = new Student[size];
            }
    
            public Student getStudent(int index) {
                return students[index];
            }
    
            // 每往 数据集合里添加一个元素,这个last就会加1
            public void addStudent(Student student) {
                this.students[last] = student;
                last++;
            }
    
            public int getLength() {
                return last;
            }
    
            // 返回一个教室迭代器,其中封装了教室自己,让迭代器可以获取教室中的数据
            public Iterator iterator() {
                return new ClassroomIterator(this);
            }
        }
    }

    这个时候,我们遍历集合的开发,实际上是面向迭代器这个接口,提供的hasNext()和next()方法,去做的开发。

    如果我们的教室类Classroom中的实现,发生了改变,比如用Map代替数组,嗯~HashMap是无序的,不能通过下标获取,因为它这个遍历是要考虑一个顺序,我不用Map来演示。

    这里用List来演示,List<Student> students;,教室类Classroom实现如下:

     1     /**教室类*/
     2     public static class Classroom implements Aggregate{
     3         //private Student[] students;
     4         private List<Student> students;
     5         // last相当于数据的长度(数组指针)
     6         private int last = 0;
     7 
     8         public Classroom(int size) {
     9             //this.students = new Student[size];
    10             this.students = new ArrayList<Student>(size);
    11         }
    12 
    13         public Student getStudent(int index) {
    14             //return students[index];
    15             return students.get(index);
    16         }
    17 
    18         // 每往 数据集合里添加一个元素,这个last就会加1
    19         public void addStudent(Student student) {
    20             //this.students[last] = student;
    21             this.students.add(student);
    22             last++;
    23         }
    24 
    25         public int getLength() {
    26             return last;
    27         }
    28 
    29         // 返回一个教室迭代器,其中封装了教室自己,让迭代器可以获取教室中的的数据
    30         public Iterator iterator() {
    31             return new ClassroomIterator(this);
    32         }
    33     }

    注意:插入代码时,不要勾选行号,否则重新编辑,复制时会连同行号一起复制,影响修改效率。

    这时,我们会发现,所有代码中,连迭代器的逻辑都不用变,因为它都是基于Classroom的接口去实现的,只是改了Classroom自己本身而已;然后Iterator去迭代集合的这段代码就更不用变了。所以,迭代器模式,它的核心的用意就是,封装你的集合迭代逻辑。即把集合迭代的逻辑,给封装在了Iterator里面,然后,对数据进行操作的一些逻辑,给封装在了Classroom这个里面,这样,在对Classroom进行迭代的时候,只要面向Iterator去编程就可以了。Classroom里面的这个(需要迭代的)集合变化了以后,实际上来说,对于迭代它的执行者(你的这个迭代方的代码),只是面向迭代器这个接口去遍历,根本就没有任何的变化。

    最后,在实际企业的应用场景里面,我们其实很少自己直接去写迭代器的模式,因为它一般都是在集合编程的时候去使用的,一般来说,我们要遍历一个集合的时候,我们会让那个集合类,返回一个这个集合对应的迭代器就可以了,而不是说直接去获取到那个集合,所以我们可以面向迭代器的这个接口去实现,因为jdk已经给我们封装好了迭代器模式了。用jdk提供给我们的iterator,改动如下:

        public static void main(String[] args) {
            Student student1 = new Student("小灵儿");
            Student student2 = new Student("小帆儿");
    
            Classroom classroom = new Classroom(2);
            classroom.addStudent(student1);
            classroom.addStudent(student2);
    
            // 这里我们遍历教室里的学生,先是拿到教室的这个迭代器,
            // 然后面向迭代器这个接口提供的hasNext()和next()方法,去做的遍历开发
            //java.util.Iterator<Student> iterator = classroom.iterator();
            java.util.Iterator iterator = classroom.iterator();
            while (iterator.hasNext()) {
                Student student = (Student) iterator.next();
                System.out.println(student);
            }
        }
    
        /**代表了一个集合类*/
        public interface Aggregate {
            // 此方法可以返回这个集合对应的一个迭代器
            //public abstract java.util.Iterator<Student> iterator();
            public abstract java.util.Iterator iterator();
        }
    
        /**教室类*/
        public static class Classroom implements Aggregate{
            ... ...
    
            /*
             * 返回一个教室迭代器,其中封装了教室自己,让迭代器可以获取教室中的的数据
             * 因为jdk已经封装了iterator模式,所以无需自己再去写一个迭代器,所以,这里我们既可以返回自己写的迭代器ClassroomIterator,
             * 也可以返回一个jdk已经给我们提供好了的List集合的iterator,迭代器再java.util包下
             */
            //public java.util.Iterator<Student> iterator() {
            public java.util.Iterator iterator() {
                return students.iterator();
            }
        }

    注意:

    1. java.util.Iterator<Student> 与 java.util.Iterator,泛型可加可不加,都不会报错,代码正常执行。

    2. 插入代码时,代码折叠起来,应该也是很优雅的。

    总结:

    1. 面向Iterator接口编程,无论底层的数据结构 和 迭代算法如果变化,调用这都不用修改代码;高内聚,低耦合,漂亮;

    2.iterator模式一般都是在集合编程中使用,尤其是如果要对集合元素遍历过程中做插入删除操作,那就用iterator,而JDK已经封装好了iterator模式,可以直接使用,是无需自己去写这个iterator模式的。除非你觉得 这个jdk提供的这个迭代器模式没有满足自己开发的需要,那么再自己去写。一般是研发底层的框架,比如提供某个数据给外部遍历,那么可以使用iterator模式自己封装迭代器。

    3.如果要对某个类中的集合进行遍历,由那个集合类返回一个iterator回来,我们统一面向iterator迭代器接口来编程遍历,提高系统整体的可维护性,可扩展性。

    end 

  • 相关阅读:
    Naive Operations HDU6315 (杭电多校2G)
    Baker Vai LightOJ
    LOJ#6278. 数列分块入门 2
    LOJ#6277. 数列分块入门 1
    Picture POJ
    Who Gets the Most Candies? POJ
    Dividing the Path POJ
    Balanced Sequence HDU
    归并排序
    Flying to the Mars
  • 原文地址:https://www.cnblogs.com/HarryVan/p/16033263.html
Copyright © 2020-2023  润新知