我想删除下面重复的源代码。
public static List<Map<String, Object>> getTransmissionTypeList() {
List<Map<String, Object>> transmissionList = new ArrayList<>();
for(EstimateTransmissionType transmissionType : EstimateTransmissionType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", transmissionType.getCode());
transmission.put("value", transmissionType.getValue());
transmission.put("name", transmissionType.getName());
transmissionList.add(transmission);
}
return transmissionList;
}
public static List<Map<String, Object>> getFuelTypeList() {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(EstimateFuelType fuelType : EstimateFuelType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
对于EstimateTransmissionType
和EstimateFuelType
,这两个枚举内部的结构完全相同。
x一个一个一个一个x一个一个二个x
我真的很想提高我的源代码质量,但我不知道从哪里开始。有人能给我一个好的灵感或明确的答案吗?
2条答案
按热度按时间ffx8fchx1#
在这里,我们可以使用新老智慧,即偏好组合而非继承。我们可以在委托类中做所有常见的事情:
现在我们可以说
EnumDemo.getAttributeMaps(EstimateTransmissionType.class)
和EnumDemo.getAttributeMaps(EstimateFuelType.class)
。chhqkbe12#
此答案相关且有帮助--https://stackoverflow.com/a/70596442/10118965
但这里有一个更直接的答案。简而言之,使用接口、枚举和泛型可以让您更容易地进行整合。
首先,创建一个包含所有相关函数的接口,我将其命名为
ParentInterface
,在本例中,您需要::getName
、::getValue
和::getCode
。接下来,你需要在接口内部创建一个方法,返回枚举的值,这是一个更复杂的步骤,因为它要求你向泛型世界迈出相当大的一步,结合枚举。
简而言之,如果我们查看枚举的JavaDoc,我们会看到以下内容。
https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/Enum.html
Class Enum<E extends Enum<E>>
所以简而言之,如果我们想说某个类型
E
是枚举,那么我们必须这样说。E extends Enum<E>
好了,现在我们知道了如何说参数化类型必须是一个枚举。我们这样做的原因是因为我们实际上想得到***枚举的值***。我们不能在没有首先确定我们有一个枚举的情况下做到这一点。
但现在我们知道了,我们可以写一个类似这样的方法。
这个方法说明我们作为参数接收的
clazz
必须是枚举类型,一旦它证明了这一点,我们就可以安全地调用Class::getEnumConstants
方法,并确保我们将得到我们所期望的结果。所以,现在我们已经写了静态方法,接下来我们在接口上放一个参数化类型。特别地,我们要确保这个接口只引用枚举。
我们将以下参数化类型添加到接口中。
<E extends Enum<E>>
最后,我们稍微修改一下静态方法,以确保它只用于为实现我们接口的枚举生成枚举值,也许你不希望这样的限制,但如果你想这样做,这里是你要添加的。
& ParentInterface<E>
这样,我们就完成了。这是我们的界面应该是大致的样子。
接下来,我们需要确保所有枚举都实现了这个新接口,这很容易做到。
x1米11米1x
public enum EstimateTransmissionType implements ParentInterface<EstimateTransmissionType>
枚举的实际内部不应该改变,你所做的只是改变外部。
最后,让我们重新编写方法,以处理这个全新的接口和重新编写的枚举。
让我们从构建
::getFuelTypeList
方法开始,这意味着我们从一个重复的,但是重命名的方法开始。除了方法名之外,此方法与
::getFuelTypeList
完全相同。让我们从修改方法签名开始,让它包含我们创建的泛型,更具体地说,让我们把这个方法引入到接口的概念中。
public static <E extends ParentInterface<E>> List<Map<String, Object>> getGenericTypeList()
但是如果我们这样做的话,编译器就会抱怨我们,说如果我们想让
E
扩展我们的接口,它也必须扩展Enum<E>
,否则就会破坏我们的接口规则。它说 “任何扩展我的东西都必须在类型参数中有一个枚举,这个枚举也扩展了我”。我们在前面将类型参数放在接口上时制定了这个规则。所以,为了克服这个问题,我们必须指定我们的类型参数也是一个枚举。这很容易改变。
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getGenericTypeList()
现在,编译器很高兴了。
因此,由于这个变化,我们的方法现在知道一个名为
E
的类型,这个类型是枚举的子类型,也是我们创建的接口的子类型。既然方法已经知道了我们的类型,让我们实际使用它。
显然,所有的东西都是硬编码的,所以让我们从改变它开始。
这几乎可以工作,但是编译器很不高兴,说它不知道在哪里可以找到
E::values
方法。令人恼火的是,Java不允许我们重写静态方法,所以这个解决方案不得不变得不必要的复杂。幸运的是,我们已经在前面完成了复杂的部分。与其尝试使用未知的E::values
方法,为什么我们不使用前面创建的静态方法呢?然而,为了使用这个方法,我们需要提供一个
Class<E>
,简单地说,我们还要修改我们的方法以接受一个Class<E>
,并且还要替换那个刚刚抛出错误的未知方法。然后应该就是这样了。现在你可以删除不必要的方法,这些方法只对单个枚举有效。下面是完整的解决方案,包括一些重构、重命名和一般清理。
这个完整的示例有一个main方法,因此您可以自己运行它并查看它是否工作。
最后,如果你决定让这个方法为你将来添加的其他枚举工作,这是非常容易做到的。只要确保你添加的每个枚举实现你的接口,并且那个接口的参数化类型应该是枚举名本身。如果这没有意义,只要遵循与其他枚举相同的格式,它应该工作得很好。