设计查询 - 使用 Java 泛型进行代码重复
Design query - Using Java Generics for code duplication
问题
我正在尝试设计两种过滤列表的方法
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
}
问题是这两种方法都有重复的代码,除了过滤部分,我在 TypeA 和 TypeB 中访问不同的参数。
到目前为止我尝试过的事情
- 我试过制作这样的通用方法。但是这个不支持
TypeA 和 TypeB 以外的类型。鼓励某人称呼它
具有非预期类型的方法。
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 方法的意外调用,同时仍然
使用泛型避免代码重复。
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
}
- 试图让两个 classes 实现一个公共接口并使用
该接口作为我的方法的输入参数。但其中之一
class 是第三方,不受我控制。
需要帮助
我真的是设计新手。想了解我的推理是否正确。还寻找有关解决此问题的替代最佳方法的建议。提前致谢。
假设您有这 2 TypeX
没有继承的接口 link 并且具有相同的方法签名。
interface TypeA {
String methodFromA();
}
interface TypeB {
String methodFromB();
}
您可以声明一个枚举,它知道必须为每个 TypeX 接口调用哪个方法。
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);
}
最后,在您的过滤器方法中,您只需要使用 TypeX class 恢复枚举实例并在其上调用适当的方法。
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
}
}
适当的结构不反射,不使用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
}
这正是 Predicate<T>
功能接口旨在解决的问题类型。
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()
;
}
}
问题
我正在尝试设计两种过滤列表的方法
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
}
问题是这两种方法都有重复的代码,除了过滤部分,我在 TypeA 和 TypeB 中访问不同的参数。
到目前为止我尝试过的事情
- 我试过制作这样的通用方法。但是这个不支持 TypeA 和 TypeB 以外的类型。鼓励某人称呼它 具有非预期类型的方法。
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 方法的意外调用,同时仍然 使用泛型避免代码重复。
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
}
- 试图让两个 classes 实现一个公共接口并使用 该接口作为我的方法的输入参数。但其中之一 class 是第三方,不受我控制。
需要帮助
我真的是设计新手。想了解我的推理是否正确。还寻找有关解决此问题的替代最佳方法的建议。提前致谢。
假设您有这 2 TypeX
没有继承的接口 link 并且具有相同的方法签名。
interface TypeA {
String methodFromA();
}
interface TypeB {
String methodFromB();
}
您可以声明一个枚举,它知道必须为每个 TypeX 接口调用哪个方法。
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);
}
最后,在您的过滤器方法中,您只需要使用 TypeX class 恢复枚举实例并在其上调用适当的方法。
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
}
}
适当的结构不反射,不使用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
}
这正是 Predicate<T>
功能接口旨在解决的问题类型。
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()
;
}
}