在 Java 中违反了 DRY 原则
Violation of DRY principle in Java
我有三种方法可以按字段过滤一组设备。
public void filtrateByType(Device[] devices, String type) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (devices[i].getType() == null && type == null) {
continue;
} else if (devices[i].getType() == null) {
devices[i] = null;
continue;
}
if (!devices[i].getType().equals(type)) {
devices[i] = null;
}
}
}
其他方法类似。唯一的区别是调用应用过滤的另一个 getter 字段。例如,调用 getModel()
而不是 getType()
。这是否违反了 DRY 原则,我该如何更改它以使其不(没有泛型)?
P.S.
这是一项家庭作业,不幸的是我们还没有使用泛型。我也无法更改方法的签名。我有一个线索,我可以使用一种方法创建内部 class ,该方法将调用 needed getter 和 return 一个值。所以,我需要把我所有的检查都放在这个方法中,但我真的不明白我的逻辑是怎么做的(尤其是 "continue")。
也许一些 Java 8 魔法会有所帮助:
public void filtrateByType(Device[] devices, String type) {
filtrateBy(devices, Device::getType, type);
}
public void filtrateBy(Device[] devices, Function<? super Device, String> attributeGetter, String attribute) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (attributeGetter.apply(devices[i]) == null && attribute == null) {
continue;
} else if (attributeGetter.apply(devices[i]) == null) {
devices[i] = null;
continue;
}
if (!attributeGetter.apply(devices[i]).equals(attribute)) {
devices[i] = null;
}
}
}
您可以创建如下所示的 interface DeviceValueExtractor
:
@FunctionalInterface
public interface DeviceValueExtractor {
Object extractValue(Device device);
}
现在将您的方法重写为:
public void filterByType(Device[] devices, DeviceValueExtractor extractor, Object expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.extractValue(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}
用法:
filterByType(devices, Device::getType, "Hello");
注意: 我使用了 Object
因为要求没有泛型 - 因为唯一调用的方法是 equals
这实际上没什么大不了的.
然而,为了更多的类型安全,您可以引入泛型(并取消 DeviceValueExtractor
:
public static <T> void filterByType(Device[] devices, Function<Device, T> extractor, T expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.apply(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}
这是更简单的版本。您可以使用原始类型,但这更容易出错。
public static <T> void filtrateByType(T[] objects, Function<T, String> function, String type) {
if (objects == null || type == null)
return;
for (int i = 0; i < objects.length; i++) {
if (objects[i] == null) continue;
String match = function.apply(objects[i]);
if (match == null || !match.equals(type))
objects[i] = null;
}
}
但是,我怀疑您真正想要的是使用 Stream API
Device[] filtered = Stream.of(devices)
.filter(d -> Objects.equals(d.getType(), type))
.toArray(Device[]::new);
我有三种方法可以按字段过滤一组设备。
public void filtrateByType(Device[] devices, String type) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (devices[i].getType() == null && type == null) {
continue;
} else if (devices[i].getType() == null) {
devices[i] = null;
continue;
}
if (!devices[i].getType().equals(type)) {
devices[i] = null;
}
}
}
其他方法类似。唯一的区别是调用应用过滤的另一个 getter 字段。例如,调用 getModel()
而不是 getType()
。这是否违反了 DRY 原则,我该如何更改它以使其不(没有泛型)?
P.S. 这是一项家庭作业,不幸的是我们还没有使用泛型。我也无法更改方法的签名。我有一个线索,我可以使用一种方法创建内部 class ,该方法将调用 needed getter 和 return 一个值。所以,我需要把我所有的检查都放在这个方法中,但我真的不明白我的逻辑是怎么做的(尤其是 "continue")。
也许一些 Java 8 魔法会有所帮助:
public void filtrateByType(Device[] devices, String type) {
filtrateBy(devices, Device::getType, type);
}
public void filtrateBy(Device[] devices, Function<? super Device, String> attributeGetter, String attribute) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (attributeGetter.apply(devices[i]) == null && attribute == null) {
continue;
} else if (attributeGetter.apply(devices[i]) == null) {
devices[i] = null;
continue;
}
if (!attributeGetter.apply(devices[i]).equals(attribute)) {
devices[i] = null;
}
}
}
您可以创建如下所示的 interface DeviceValueExtractor
:
@FunctionalInterface
public interface DeviceValueExtractor {
Object extractValue(Device device);
}
现在将您的方法重写为:
public void filterByType(Device[] devices, DeviceValueExtractor extractor, Object expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.extractValue(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}
用法:
filterByType(devices, Device::getType, "Hello");
注意: 我使用了 Object
因为要求没有泛型 - 因为唯一调用的方法是 equals
这实际上没什么大不了的.
然而,为了更多的类型安全,您可以引入泛型(并取消 DeviceValueExtractor
:
public static <T> void filterByType(Device[] devices, Function<Device, T> extractor, T expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.apply(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}
这是更简单的版本。您可以使用原始类型,但这更容易出错。
public static <T> void filtrateByType(T[] objects, Function<T, String> function, String type) {
if (objects == null || type == null)
return;
for (int i = 0; i < objects.length; i++) {
if (objects[i] == null) continue;
String match = function.apply(objects[i]);
if (match == null || !match.equals(type))
objects[i] = null;
}
}
但是,我怀疑您真正想要的是使用 Stream API
Device[] filtered = Stream.of(devices)
.filter(d -> Objects.equals(d.getType(), type))
.toArray(Device[]::new);