2010-02-03 28 views
3

列表讓每個對象的屬性列表時,我有一個看起來像這樣幾個對象:的Java代碼,防止重複從對象

class PhoneNumber 
{ 
    String getNumber(); 
    String getExtension(); 
    DateTime getLastCalled(); 
} 
class Address 
{ 
    String getCity(); 
    string getState(); 
    int getZip(); 
} 

我希望能夠採取的列表任何一個這些對象並獲得特定屬性的列表。如果我要爲每個屬性編寫函數,這是一個簡單的操作,但據我瞭解,很多次重複代碼是不好的做法。

所以我希望能夠爲任一對象的財產做這樣的事情:

List<Address> AddressList = getAddresses(); 
List<String> CityList = getListOfProperties(AddressList, Address.getCity /*<--Instruction as to what property to populate the returned list with */) 

我絞盡腦汁想嘗試與泛型做到這一點。我甚至不確定這是否可行,但據我瞭解,使用Java編程語言可以完成很多神奇的事情。

回答

2

您可以使用泛型和實用程序類來完成此工作。我喜歡這個比使用反射好一點,因爲你會在編譯時檢查你正在檢索的屬性是否存在(並且不會拼寫錯誤等)。

首先進行實際轉換的類。請注意,當我們調用getListOfProperties()時,我們將在匿名內部類中重寫的抽象「get」方法。

public abstract class ListPropertyGetter<R,T> 
{ 
    /** Given a source object, returns some property of type R. */ 
    public abstract R get(T source); 

    /** Given a list of objects, use the "get" method to retrieve a single property 
     from every list item and return a List of those property values. */ 
    public final List<R> getListOfProperties(List<T> list) 
    { 
    List<R> ret = new ArrayList<R>(list.size()); 
    for(T source : list) 
    { 
     ret.add(get(source)); 
    } 
    return ret; 
    } 
} 

然後你就這樣使用它。不是一個漂亮的班輪,但編譯時檢查善良:

List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); 
// add some PhoneNumbers to the list 
List<String> extensions = 
    new ListPropertyGetter<String, PhoneNumber>() 
    { 
    @Override 
    public String get(PhoneNumber source) 
    { 
     return source.getExtension(); 
    } 
    }.getListOfProperties(phoneNumbers); 
+0

男人,在我放棄併發布這個問題之前,我非常接近類似的東西。太感謝了! – 2010-02-03 21:27:41

+0

您的'ListPropertyGetter'類是通用的,足以對輸入項執行任何操作以生成輸出項,而不僅僅是獲取屬性。這通常被稱爲'map'(除了Linq,它被稱爲'Select')。 – 2010-02-03 22:15:12

2

您可以使用Introspector來處理您的對象,如this SO answer

public <T > List<T > getMemberList(List<? > beanList, 
     String propertyName, Class<T > resultClass) throws Exception { 
    List<T > result = new ArrayList<T >(); 
    for(Object bean : beanList) { 
     result.add((T)new PropertyDescriptor( 
       propertyName, bean.getClass()).getReadMethod().invoke(bean)); 
    } 
    return result; 
} 

然後你就可以像這樣的電話:

List<String > result = getMemberList(phonenumberList, "number", String.class); 
2

對於一些這個簡單,你最好只提供getter和setter方法。拒絕複製一行代碼會節省很多。更好的是,讓你的IDE爲你寫。

+0

只要您提供存取方法,就會引發代碼重複。 – 2010-02-22 17:54:20

1

您可以使用反射(java.lang.Class和java.lang.reflect。*)來獲取方法名稱;以「get」開頭的是屬性,其名稱跟隨「get」。

1

對於Java中的閉包來說,這是一個很好的例子;它來了,但它還沒有到。

與此同時,你可以用反射做到這一點,雖然反射總是會有性能損失。反射可以做的一件事是讓你調用一個對象的方法,或者通過指定方法/屬性的名稱作爲一個字符串來檢索一個屬性;在你的情況下,你會想要做getListOfProperties(AddressList, "city")並在該方法中使用反射來檢索指定的屬性。

通過使用Apache Commons BeanUtils庫,可以大幅簡化此類事物。

import org.apache.commons.beanutils.BeanUtils; 

static List<String> getListOfProperties(List beans, String propertyName) { 
    List<String> propertyValues = new ArrayList<String>(); 
    for (Object bean:beans) { 
     propertyValues.add(BeanUtils.getProperty(bean, propertyName)); 
    } 
    return propertyValues; 
}