对于这种情况,这是合适的设计吗?

Would this be appropriate design for this situation?

我正在一个未排序的链表和一个已排序的链表中实现 remove(Object o) 方法。这两个 类 都扩展了 AbstractLinkedList(代码重用)

这是我在未排序链表中删除(对象 o)的代码

@Override
public void remove(E value) {
    if(front != null) {
        if(front.data.equals(value)) {
            front = front.next;
        } else {
            ListNode<E> current = front;
            boolean hasRemovedElement = false;
            while(current.next != null && !hasRemovedElement) {
                if(current.next.data.equals(value)) {
                    current.next = current.next.next;
                    hasRemovedElement = true;
                }
                current = current.next;
            }
        }
    }
}

以及我在排序链表中删除(对象 o)的代码

public void remove(E value) {
    if(front != null) {
        ListNode<E> current = front;
        if(front.data.equals(value)) {
            front = front.next;
        } else {
            boolean hasRemovedElement = false;
            while(current.next != null && !hasRemovedElement 
                    && current.next.data.compareTo(value) >= 0) {
                if(current.next.data.equals(value)) {
                    current.next = current.next.next;
                    hasRemovedElement = true;
                }
                current = current.next;
            }
        }
    }

我立即注意到我的两种方法中的代码几乎相同。已排序链表中的 remove(Object o) 只是再进行一次条件检查,说明下一个元素是否小于您要删除的值,您要删除的元素不可能在列表中。我为利用代码重用所做的是在 AbstractLinkedList 中实现一个两个列表都可以调用的重载版本,即

@Override
protected void remove(E value, E toCheckAgainst) {
    if(front != null) {
        ListNode<E> current = front;
        if(front.data.equals(value)) {
            front = front.next;
        } else {
            boolean hasRemovedElement = false;
            while(current.next != null && !hasRemovedElement 
                    && current.next.data.compareTo(toCheckAgainst) >= 0) {
                if(current.next.data.equals(value)) {
                    current.next = current.next.next;
                    hasRemovedElement = true;
                }
                current = current.next;
            }
        }
    }

在未排序的链表中

@Override
public void remove(E value) {
      remove(value, CHECKER)
}

但我的问题是我应该如何在未排序的链表中创建此 CHECKER?就排序链表而言,这个检查器可以再次成为值。如果您达到小于检查器(已排序)的值,检查器的作用基本上是停止迭代。我可以使检查器不对未排序的链表产生任何影响有什么价值?我尝试使用像 MIN POSSIBLE = -9999999 这样的 int,但你不能将 int 与泛型进行比较。或者在设计方面更好,只是在 类.

中具有几乎相同的实现

我的建议是让方法保持原样。代码重用应与可读性等进行权衡

但是假设您无论如何都想这样做,我会使用某种测试仪(或者在 Java 8 中,Predicate)。您在超类中声明这样的接口:

protected interface Tester<E> {
    public boolean test(E testObj);
}

那么您的一般删除方法是:

protected void remove(E value, Tester<E> extraCondition) {
    if(front != null) {
        ListNode<E> current = front;
        if(front.data.equals(value)) {
            front = front.next;
        } else {
            boolean hasRemovedElement = false;
            while(current.next != null && !hasRemovedElement 
                    && extraCondition.test(current.next.data) {
                if(current.next.data.equals(value)) {
                    current.next = current.next.next;
                    hasRemovedElement = true;
                }
                current = current.next;
            }
        }
    }
}

然后在您的未排序列表中,您将拥有:

@Override
public void remove(final E value) {
    remove(value, new Tester<E>() {
        public boolean test(E testObj) {
            return true;
        }
    });
}

在您的排序列表中:

public void remove(final E value) {
    remove(value, new Tester<E>() {
        public boolean test(E testObj) {
            return testObj.compareTo(value) >= 0;
        }
    });
}

因此,在未排序的列表中,您传递了一个始终 returns 为真的条件,而在排序的列表中,您传递了一个基于与值的比较 returns 为真的条件。

您先测试 null 然后再进行比较的想法可行,但是:

  • 它使它更难读。
  • 它只适用于这种特殊情况。如果您有一个按降序排序的列表怎么办?或者有一些奇特的东西,比如特殊的 "stop" 元素,您只能在其中删除 "stop" 元素之前的元素?

一般情况下,不要将仅属于您当前能想到的子类的特殊行为放在您的超类中,只是为了在子类中节省一些编码。