对于这种情况,这是合适的设计吗?
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" 元素之前的元素?
一般情况下,不要将仅属于您当前能想到的子类的特殊行为放在您的超类中,只是为了在子类中节省一些编码。
我正在一个未排序的链表和一个已排序的链表中实现 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" 元素之前的元素?
一般情况下,不要将仅属于您当前能想到的子类的特殊行为放在您的超类中,只是为了在子类中节省一些编码。