#java #inheritance #polymorphism #abstract-class
#java #наследование #полиморфизм #абстрактный класс
Вопрос:
Я создаю класс Node для использования в двух похожих, но принципиально разных алгоритмах. Имея некоторую общую функциональность между ними, моя идея заключалась в создании абстрактного класса node с общими методами и полями. Расширьте из этого абстрактного класса два конкретных подкласса WaveNode и EchoNode.
Некоторые методы в абстрактном классе имеют дело с экземплярами узла, но я хотел использовать этот общий код с экземпляром подкласса, то есть, если вы даете методу WaveNode или EchoNode, тогда методу не нужна другая реализация. Поэтому я подумал, что лучше всего реализовать его в абстрактном классе, и оба подкласса могут использовать реализацию, поэтому мне не нужно вводить ее дважды. Однако, когда я нахожусь в своем подклассе и имею дело с WaveNode или EchoNode, я получаю ошибки компиляции, потому что метод ожидает экземпляр абстрактного узла. Есть ли способ реализовать метод в суперклассе, и разные классы, расширяющие суперкласс, могут использовать его реализацию.
Пример приведен ниже.
Set<Node> getNeighs(){
Set<Node> nei = (Set<Node>) rec.keySet();
nei.remove(this);
return nei;
}
Этот код принимает карту «rec» и помещает набор ключей (узла) в набор узлов. Удаляет текущий узел и возвращает все его соседние узлы. Таким образом, и WaveNode, и EchoNode используют один и тот же код. Единственное отличие заключается в том, что набор будет иметь 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);
}
Пожалуйста, имейте в виду, что сейчас у меня все работает так, как задумано, я сам виноват в том, что не привел возвращаемый тип узла к TreeNode. Однако любые комментарии к моему коду «делают слишком много» или аналогичные советы по очистке моего кода приветствуются. Спасибо
Комментарии:
1. Можете ли вы опубликовать весь свой фактический код (удалить несвязанные части) и сообщение об ошибке
2. Однако метод, который вы показали, не принимает параметры. Как он принимает
rec
?3. Я думаю, что вы хотите использовать какой-то тип в абстрактном классе (т. Е.
EchoNode extends AbstractXXX<EchoNode>
), Но я не уверен4. Извините, ребята, мне просто нужно было привести возвращаемый тип метода, возвращающего узел в TreeNode. Я думал, что это опасно, так как вы должны стараться избегать отбрасывания, но, похоже, это работает и не дает мне ошибок. В настоящее время я изучаю наследование, поэтому, возможно, ошибка новичка. Спасибо
Ответ №1:
Используйте generics для этого вместо того, чтобы вводить текст конкретно в Node. Измените возвращаемую сигнатуру с Set<Node>
на Set<? extends Node>
или попросите подкласс обрабатывать общий тип, а не его тип.
Ответ №2:
Set<WaveNode>
or Set<EchoNode>
не является подклассом Set<Node>
и не может быть приведен к нему; и вы не можете вызывать remove(WaveNode ..)
с аргументом типа суперкласса ( Node
) . Если бы у вас было keySet
так, как Set<Node>
это было бы нормально, или используйте необработанный тип: Set nei = rec.keySet();
Ответ №3:
пытаясь быть более полезным, я попытался интуитивно понять суть проблемы и найти работоспособное решение. есть много более сложных моментов, которые мог бы выполнить код (см., 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);
}
}