利用Iterator模式遍历JavaBean中的属性

缘起 (Motivation/intent)

JavaScript中能够遍历对象中的属性,但Java却没有这样的语言支持。例如一个普通POJO对象UserBeanjava

public class UserBean {

    private int id;

    private String name;

    private Date birthdate;

 

   // getters & setters

}

 

如今想遍历对象中每一个属性,得到以下的效果设计模式

UserBean user = new UserBean(1234, "张三", "1982-12-13");

for(Object propertyValue : user) {

     System.out.println(propertyValue);

}

 

将显示数组

1234ide

张三工具

1982-12-13this

 

解决方案 (Solution)

使用Iterator模式。要使某个对象能够进行遍历循环操做,亦便可以适用于foreach,该对象必须实现Iterable接口。这个接口将会强制实现iterator()方法。spa

public class UserBean implements Iterable<Object> {

...

@Override

public Iterator<Object> iterator() {}

}

 

实现Iterator的步骤以下设计

1. 在iterator()方法中,实例化咱们本身的Iterator实现类,这里称之为MyObjectPropertyIterator

2. 要获取任何JavaBean对象的信息,既能够利用反射,也能够利用java.beans.Introspector这个工具类来获取一个BeanInfo对象

// 2.1.1  
BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());

//    2.1.2  从BeanInfo对象中,咱们能够得到一个PropertyDescriptor数组,其中就包含了bean对象中全部属性信息

           PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();


  //  2.1.3  而后用PropertyDescription的readMethod方法得到其getter和setter,最后调用invoke方法获得返回结果

            for(PropertyDescriptor propertyDescriptor : propertyDescriptors)


                Object propertyValue = propertyDescriptor.getReadMethod().invoke(targetObject);

               System.out.println(propertyValue);


            }


    // 与咱们的遍历对象属性无关没有实现的必要
    @Override
    public void remove() {}







   /*若是使用反射,则代码以下:*/

//   2.2.1  
Field[] fields = user.getClass().getDeclaredFields();

//   2.2.2 遍历Field[]数组

           for(Field field : fields) {

               field.setAccessible(true); // 这句使咱们能够访问似有成员变量

               Object property = field.get(user);


           }

 

3. 利用步骤3的思路,建立咱们的Iterator实现

public class MyPropertyIterator implements Iterator<Object>{
    private int index;
    private Object targetObject;
    PropertyDescriptor[] propertyDescriptors;
   

    // 经过构造器传入所要遍历的对象,即UserBean的对象
    PropertyIterator(Object targetObject) {
        this.targetObject = targetObject;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(targetObject.getClass());
            propertyDescriptors = beanInfo.getPropertyDescriptors();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean hasNext() {
        return this.index < this.propertyDescriptors.length;
    }

    @Override
    public Object next() {
        Object propertyValue = null;
        try {
            PropertyDescriptor propertyDescriptor = propertyDescriptors[index++];
            propertyValue= propertyDescriptor.getReadMethod().invoke(targetObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return propertyValue;
    }

//若是用反射

public class PropertyIterator implements Iterable<Object> {
    private final Object targetObject;
    
    public PropertyIterator(final Object targetObject) {
        this.targetObject = targetObject;
    }
    
    public Iterator<Object> iterator() {
        return new PropertyIteratorImpl();
    }
    private class PropertyIteratorImpl implements Iterator<Object>{
        int index;
        Field[] fields;

        PropertyIteratorImpl() {
            try {
                fields = targetObject.getClass().getDeclaredFields();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean hasNext() {
            return this.index < this.fields.length;
        }

        @Override
        public Object next() {
            Object obj = null;
            try {
                Field field = fields[index++];
                field.setAccessible(true);
                obj = field.get(targetObject);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }

        @Override
        public void remove() {}
    }
}

 

 

4. 在UserBean的iterator方法中,返回MyPropertyIterator的实例化对象。 

@Override

    public Iterator<Object> iterator() {

        return new  MyPropertyIterator(this);

    }

说明 (Note)

为了简明,没有说明Iterator设计模式的实现原理,关于这部分,请参考有关设计模式的书籍,特别是GoF。或可参考java.util.LinkedList API的源代码。code

 

评估 (Assessment)

对目标对象彻底没有侵入性,将遍历功能与目标对象自己分离。上一个版本,让UserBean对象直接实现Itarable,虽然更直观,代码量也少,但通用型不强,有侵入性。若是不是本身建立的类,没法使用。这个版本将Iterator类的实现分离成单独一个类,使之更通用化。如今的版本已经不须要Bean对象实现Iterable接口,使得UserBean类更干净、纯粹,不牵涉和UserBeen业务无关的任何接口或抽象类,符合将变化点分离的OO设计思想。对象

另外,BeanInfo版本和反射版本有细微差异:BeanInfo的PropertyDescriptor经过getter读取类变量,而反射则直接读取似有成员变量。后者显得更暴力些。虽然从代码编写者的角度彷佛更方便,但破坏了OO的封装和信息隐藏原则。

 

本篇笔记的目的是灵活使用Iterator模式。和大多数书本或网上教程不一样,本篇利用Iterator模式实现了一个非Collection类的遍历。

相关文章
相关标签/搜索