我正在创建一个Node类,用于两个相似但根本不同的算法。在它们之间有一些共同的功能,我的想法是创建一个带有共享方法和字段的抽象节点类。从这个抽象类扩展了两个具体子类的WaveNode和EchoNode。
抽象类中的一些方法处理Node的实例,但是我想将这个公共代码用于子类的实例,也就是说,如果你给方法一个WaveNode或一个EchoNode,那么这个方法不需要一个不同的实现。所以我认为最好在抽象类中实现它,并且两个子类都可以使用实现,所以我不必输出两次。但是,当我在我的子类中并且我正在处理WaveNode或EchoNode时,我遇到了编译错误,因为该方法需要一个抽象的Node实例。有没有办法在超类中实现一个方法,而扩展超类的不同类可以使用它的实现。
以下是一个例子。
Set<Node> getNeighs(){
Set<Node> nei = (Set<Node>) rec.keySet();
nei.remove(this);
return nei;
}
此代码采用映射“rec”并将键集(节点)放入一组节点。删除当前节点并返回其所有邻居。所以WaveNode和EchoNode都使用完全相同的代码。唯一不同的是Set将是WaveNode或EchoNode。我想用超类中的Node实现它,以节省我两次编写它。有可能吗?
修改
发布更多代码:
public abstract class Node {
private final int id;
Map<Node, Boolean> rec = new HashMap<Node, Boolean>();
public Node(int id) {
this.id = id;
}
int getId() {
return id;
}
void addNeigh(Node neigh) {
rec.put(neigh, false);
}
Set<Node> getNeighs() {
Set<Node> nei = (Set<Node>) rec.keySet();
nei.remove(this);
return nei;
}
void printNeighbours() {
Set<Node> nei = getNeighs();
System.out.println(this +" neighbours are: " + nei);
}
Node getSilentNeigh() {
for(Entry<Node, Boolean> entry : rec.entrySet())
{
if(!entry.getValue())
return entry.getKey();
}
return null;
}
public final class TreeNode extends Node {
boolean messageSent = false;
public TreeNode(int id){
super(id);
}
public void sendTok(TreeNode sender){
rec.put(sender, true);
}
请注意,我现在按预期工作,因为没有将Node的返回类型转换为TreeNode,这是我自己的错。但是,欢迎任何关于我的代码“做太多”的评论或关于清理我的代码的类似建议。感谢
答案 0 :(得分:1)
使用泛型执行此操作,而不是专门在Node上键入。将返回签名从Set<Node>
更改为Set<? extends Node>
,或让子类处理泛型类型而不是其类型。
答案 1 :(得分:0)
Set<WaveNode>
或Set<EchoNode>
不是 Set<Node>
的子类,无法将其转换为它;并且您不能使用超类类型(remove(WaveNode ..)
)的参数调用Node
。如果您keySet
为Set<Node>
,那就没问题,或使用原始类型:Set nei = rec.keySet();
答案 2 :(得分:0)
试图更有帮助,我试图直觉问题的精神,并提出一个可行的解决方案。代码COULD已经完成了许多更复杂的要点(参见上面的Nosretep),但过多的细节可能会影响初学者学习要点;因此,此代码仅提示简单的工作方法。
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
/* this class does everything that EVERY Node does since it defines what that means; for
* ANY behaviors that are common to subclasses, here is where they should be implemented.
*/
abstract class Node {
private final int id;
private boolean tokenSent = false;
public Node(int id) {
this.id = id;
}
int getId() {
return id;
}
// common behavior: other things that a Node might wish to do in context of the problem
public void sendTok() {
if (!tokenSent) {
// send token here
tokenSent = true;
}
}
/* common behavior: this is not really the ideal way to do this, but hopefully it makes
* sense in the context of the problem being solved; better would be an iterator that
* visits each node in the list and performs the printing, etc., but this is in the
* spirit of the problem
*/
public void printNeighboursOf(List<Node> list) {
if (list.size() > 1) {
System.out.print(this + "[" + getId() + "] has neighbors: ");
Node node;
Iterator<Node> iterator = list.iterator();
while (iterator.hasNext()) {
node = iterator.next();
if (!node.equals(this))
System.out.print(node + "[" + node.getId() + "] ");
}
} else {
System.out.print(this + " has no neighbors");
}
System.out.println();
}
/* this method has no implementation in this class (hence its being abstract); each
* subclass MUST implement it (or their subclasses!), allowing differing algorithms.
* the signature (method name and parameter list) must be identical for every subclass
*/
public abstract int doSomeNodeBehavior();
}
/* this class knows and does everything a Node knows and does, and adds a bit more; it
* can do additional things differently or other than what EchoNode does
*/
class WaveNode extends Node {
public WaveNode(int id) {
super(id);
}
public void doWaveBehavior() {
// do something wavy here
}
public int doSomeNodeBehavior() {
// do the wave algorithm
return 0;
}
}
/* this class knows and does everything a Node knows and does, and adds a bit more
* can do additional things differently or other than what WaveNode does
*/
class EchoNode extends Node {
public EchoNode(int id) {
super(id);
}
public void doEchoBehavior() {
// do something echoy here
}
public int doSomeNodeBehavior() {
// do the echo algorithm
return 0;
}
}
/* it is best to reduce the amount of behavior the Node container (ArrayList in this case)
* does beyond what is typical for an Abstract Data Type (ADT) element; make the additional
* behavior in other classes. visit each node to perform specific behaviors and let the
* polymorphic behavior determine exactly what to do. Note: subclass specific behavior is
* not possible without downcasting, and that MAY be a sign of poor design
*/
public class Nodes {
public static void main(String[] args) {
List<Node> list = new ArrayList<Node>();
list.add(new WaveNode(1));
list.add(new WaveNode(2));
Node node = new EchoNode(1);
list.add(node);
list.add(new EchoNode(2));
node.printNeighboursOf(list);
}
}