Indexer
これを提案するのは躊躇しますが、提供されたオブジェクトのフィールドを使用して、リフレクションを介して単一のマップを自動生成するある種のクラスの背後にルックアップをカプセル化することができます。
単一のマップとは、フィールド名とデータの両方に基づいてキーを作成するインデクサー全体の単一のマップを意味します (たとえば、フィールド名を表す文字列をデータの文字列表現と連結します)。
インデクサーに対するルックアップは、フィールド名とデータ値の両方を提供し、インデクサーによってカプセル化された単一のマップでルックアップされます。
これは、インデクサーが代わりにマップのマップ(フィールド名のマップからデータのマップへのマップ) に支えられている同様のソリューションよりも必ずしも利点があるとは思いません。
インデクサーは注釈を使用するように設計することもできます。これにより、すべてのフィールドが索引付けされるわけではなく、適切に注釈が付けられたフィールドのみが索引付けされます (またはその逆で、注釈を使用してフィールドを除外します)。
全体として、マップ ソリューションのマップは、複雑なキー アセンブリのステップ (特定のフィールド データ タイプでは複雑になる可能性があります) を省略できるため、簡単だと思います。どちらの場合でも、マップを自動生成する にすべてをカプセル化するのIndexer
が最善の方法のようです。
アップデート:
型クラスの一般化されていない概念の簡単な証明を行いましたIndexer
(map of maps アプローチを使用)。 これは決して完成した作品ではありませんが、上記の概念を示しています。主要な欠点の 1 つは Bean への依存であるため、アクセサー メソッドのないパブリック フィールドとプライベート フィールドの両方がこのインデクサーから見えません。
public class Indexer
{
private Map<String,Map<Object,Set<Object>>> index = new HashMap<String,Map<Object,Set<Object>>>();
// Add an object to the index, all properties are indexed.
public void add(Object object) throws Exception
{
BeanInfo info = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
for (PropertyDescriptor descriptor : propertyDescriptors)
{
String fieldName = descriptor.getName();
Map<Object,Set<Object>> map = index.get(fieldName);
if (map == null)
{
map = new HashMap<Object,Set<Object>>();
index.put(fieldName, map);
}
Method method = descriptor.getReadMethod();
Object data = method.invoke(object);
Set<Object> set = map.get(data);
if (set == null)
{
set = new HashSet<Object>();
map.put(data, set);
}
set.add(object);
}
}
// Retrieve the set of all objects from the index whose property matches the supplied.
public Set<Object> get(String fieldName, Object value)
{
Map<Object,Set<Object>> map = index.get(fieldName);
if (map != null)
{
Set<Object> set = map.get(value);
if (set != null)
{
return Collections.unmodifiableSet(set);
}
}
return null;
}
}