I have a small set of Java POJOs, each them has several fields. I do not plan to add fields to them on the fly. Size of my set is small: it's not about some "bigdata", but rather about state of my application. I.e my data holder class looks like
class MyObject
{
private int a
private String b
private boolean c
}
I need some datastructure which can help me to make queries to this data by some field values: by a=5, b="abc" or c=true. For now it's OK to query by one fields only, i.e. I don't need complex queries.
A straightforward solution is to use maps:
Map<Integer, MyObject> aMap = new HashMap<>()
Map<String, MyObject> bMap = new HashMap<>()
Map<Boolean, MyObject> cMap = new HashMap<>()
The questions are:
Instead of creating a separate data structure You can use a Specification Pattern to evaluate if an object satisfy a condition, using this pattern you can do any sort of combination and define even more complex rules
Here is an example (Kotlin version) :
import java.util.Objects
interface Specification<T> {
fun isSatisfiedBy(obj: T): Boolean
}
class Or<T>(private val spec1: Specification<T>, private val spec2: Specification<T>) : Specification<T> {
override fun isSatisfiedBy(obj: T) = spec1.isSatisfiedBy(obj) || spec2.isSatisfiedBy(obj)
}
class And<T>(private val spec1: Specification<T>, private val spec2: Specification<T>) : Specification<T> {
override fun isSatisfiedBy(obj: T) = spec1.isSatisfiedBy(obj) && spec2.isSatisfiedBy(obj)
}
class FieldValue<T, V>(private val property: (T)->V, private val value: V): Specification<T> {
override fun isSatisfiedBy(obj: T) = property(obj) == value
}
and you can use it like this :
fun main() {
val myObjects: List<MyObject> = listOf(
MyObject(1, "abc", true),
MyObject(2, "def", false),
MyObject(3, "abc", false),
MyObject(4, "ghi", true),
MyObject(5, "abc", true)
)
// check the following condition a=5 OR (b=abc AND c = true)
val spec: Specification<MyObject> = Or(
FieldValue(MyObject::a, 5),
And(
FieldValue(MyObject::b, "abc"),
FieldValue(MyObject::c, true)
)
)
val results = myObjects.filter(spec::isSatisfiedBy)
}
Now this will filter on the fly your list so you need only to maintain your initial list of MyObject