オブジェクトのリストから、各オブジェクトのプロパティのリストを取得するJava防止のコードの重複
-
25-09-2019 - |
質問
私はこのようになり、いくつかのオブジェクトを持っています
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プログラミング言語で行うことができます。
解決
あなたは仕事をするためにジェネリック医薬品とユーティリティクラスでこれを行うことができます。少し良く反射を使用するよりも、このような私、あなたがプロパティを使用している検索が存在することをコンパイル時のチェックを取得しているため(となどをスペルミスされていません。)。
まず、実際の変換を行いますクラス。抽象的には、我々は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;
}
}
次に、あなたはこのようにそれを使用しています。ないきれいな1ライナーが、コンパイル時の良さをチェックします:
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);
他のヒント
は、より良いオフだけゲッターとセッターを提供する何か、このシンプルなため、あなたがしています。あなたは、コードの1行を複製するために拒否することによって多くを保存していません。さらに良いことに、ちょうどあなたのIDEがあなたのためにそれを書くために取得ます。
あなたは Introspector
であなたのオブジェクトを扱うことができますののように、このSO回答する。
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 );
あなたは、メソッド名を取得するには、リフレクションを使用することができます。名前が「取得」は以下の性質、ある「GET」。
で始まるものをこれは、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;
}