利用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類的遍歷。

相關文章
相關標籤/搜索