Problem
I am trying to design two methods that filter a list
public List<TypeA> filter(List<TypeA> typeAList) {
//duplicated code
//filter typeAList using some parameters in typeA objects
//return filtered list
}
public List<TypeB> filter(List<TypeB> typeBList) {
//duplicated code
//filter typeBList using some parameters in typeB objects
//return filtered list
}
The problem is both the methods have duplicate code except for the filtering part where I access different parameters inside TypeA and TypeB.
Things I tried so far
public <T> List<T> filter(List<T> genericList) {
//duplicated code
if (T instanceOf TypeA)
//filtering code for TypeA
if (T instanceOf TypeB)
//filtering code for TypeB
//return filtered list
}
public List<TypeA> filter(List<TypeA> typeAList) {
//call innerFilter(typeAList)
}
public List<TypeB> filter(List<TypeB> typeBList) {
//call innerFilter(typeBList)
}
private <T> List<T> innerFilter(List<T> genericList) {
//duplicated code
if (T instanceOf TypeA)
//filtering code for TypeA
if (T instanceOf TypeB)
//filtering code for TypeB
//return filtered list
}
Help needed
I'm really new to design. Want to understand if my reasoning is right behind the approaches. Also looking for suggestions on alternate best approaches to solve this problem. Thanks in advance.
The appropriate structure is not reflective, and does not use instanceof
.
public List<TypeA> filter(List<TypeA> typeAList) {
innerFilter(typeAList, typeA -> isGoodA(typeA))
}
private boolean isGoodA(TypeA a) { ... }
public List<TypeB> filter(List<TypeB> typeBList) {
innerFilter(typeBList, typeB -> isGoodB(typeB))
}
private boolean isGoodB(TypeB a) { ... }
private <T> List<T> innerFilter(List<T> genericList, Predicate<T> pred) {
//duplicated code
//filter genericList using pred
//return filtered list
}
This is exactly the type of problem that the Predicate<T>
functional interface was meant to solve.
import java.util.List;
import java.util.function.Predicate;
public class SOQ_20220501
{
public static void main(String[] args)
{
record TypeA(int a) {}
record TypeB(boolean b) {}
final List<TypeA> as = List.of(new TypeA(0), new TypeA(1), new TypeA(2), new TypeA(3), new TypeA(4));
final List<TypeB> bs = List.of(new TypeB(true), new TypeB(false));
var whateverA = filter(as, typeA -> typeA.a() % 2 == 1);
System.out.println(whateverA);
var whateverB = filter(bs, typeB -> typeB.b());
System.out.println(whateverB);
}
public static <T> List<T> filter(List<T> typeAList, Predicate<T> predicate)
{
return
typeAList.stream()
.filter(predicate)
.toList()
;
}
}
Assume you have this 2 TypeX
interface without inheritance link and with same methods signature.
interface TypeA {
String methodFromA();
}
interface TypeB {
String methodFromB();
}
You could declare an Enum who knows which method has to be called for each TypeX interface.
enum FilterType {
TYPE_A(TypeA.class){
@Override
public <T> void callMethod(T typeX) {
TypeA typeA = (TypeA) typeX;
typeA.methodFromA();
}
},
TYPE_B(TypeB.class){
@Override
public <T> void callMethod(T typeX) {
TypeB typeB = (TypeB) typeX;
typeB.methodFromB();
}
};
Class typeClass;
FilterType(Class typeClass) {
this.typeClass = typeClass;
}
public static FilterType from(Class<?> typeClass) {
return Arrays.stream(values())
.filter(filterType -> filterType.typeClass.equals(typeClass))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("FilterType for class '" + typeClass + "' not exist")),
}
public abstract <T> void callMethod(T typeX);
}
Finally, in your filter method, you just have to recover the enum instance with the TypeX class and call the appropriated method on it.
class FilterService<T> {
// The class type of TypeX interface
private final Class<T> typeClass;
public FilterService() {
// Recover the class of the generic T
this.typeClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
public List<T> filter(List<T> genericList) {
FilterType filterType = FilterType.from(typeClass); // Will throw IllegalArgumentException if T class isn't handle
genericList.forEach(typeX -> filterType.callMethod(typeX));
//return filtered list
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.