违反Java中的DRY原则

时间:2018-10-10 19:36:41

标签: java dry

我有三种方法可以按字段过滤设备阵列。

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原则,我如何才能更改它,使其不(没有泛型)?

PS 这是一项家庭作业,很遗憾,我们尚未使用泛型。我也无法更改方法的签名。我有一个线索,我可以用一种方法创建内部类,该方法将调用所需的getter并返回一个值。因此,我需要将所有检查放入这种方法中,但是我真的不理解如何用我的逻辑(特别是使用“ continue”)来完成它。

3 个答案:

答案 0 :(得分:6)

您可以创建如下所示的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;
        }
    }
}

答案 1 :(得分:1)

也许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;
        }
    }
}

答案 2 :(得分:0)

这是更简单的版本。您可以使用原始类型,但这会更容易出错。

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);