I have two classes which are as follows :
public class A{
private String id ;
private SortedMap<String,B> answer = new TreeMap<String,B>();
private String text;
}
public class B{
private String id = null ;
priva开发者_StackOverflow中文版te SortedMap<String,A> question = new TreeMap<String,A>();
private String text = null;
}
Is there any way i can remove circular dependency from the above classes..?
No there isn't but that's no problem.
There is no problem with having circular dependency in JAVA. It's quite common to have those if you want to traverse structures in both directions. Think a tree where the parent and child knows of each other thus creating a circular dependency.
The Garbage Collector will detect circular dependencies and handle this just fine.
The only problems occur when having circular dependencies in both constructors which will result in an stack overflow :)
No, unless you remove one of the maps.
Based on what you have, you don't need two classes. Try to make the class more generic and you only need one.
public class AB {
private final String id ;
private final SortedMap<String,AB> answer = new TreeMap<String,AB>();
private final String text;
private final boolean isA; // if you need to know if its an A or B.
}
If you have two classes which reference each other, javac will resolve that if you compile both at the same time:
file: dev/A.java
class A {
B b = null;
public A(B b)
{
this.b = b;
}
};
file: dev/B.java
package dev;
class B {
A a = null;
public B(A a )
{
this.a = a;
}
};
$ javac -d classes dev/A.java
dev/A.java:3: cannot find symbol
symbol : class B
location: class dev.A
B b = null;
^
dev/A.java:4: cannot find symbol
symbol : class B
location: class dev.A
public A(B b)
^
2 errors
$ javac -d classes dev/B.java
dev/B.java:3: cannot find symbol
symbol : class A
location: class dev.B
A a = null;
^
dev/B.java:4: cannot find symbol
symbol : class A
location: class dev.B
public B(A a )
^
2 errors`
but if you enter:
$ javac -d classes dev/A.java dev/B.java
it will resolve the circular compiler dependency.
(this is actually a comment, but I don't have enough reputation points to do that)
:->why would you like to do that?
because findbugs says so in Pattern: CD_CIRCULAR_DEPENDENCY:
This class has a circular dependency with other classes. This makes building these classes difficult, as each is dependent on the other to build correctly. Consider using interfaces to break the hard dependency.
also wikipedia says: ...in software design circular dependencies between larger software modules are considered an anti-pattern because of their negative effects... Circular dependencies are often introduced by inexperienced programmers...
public class A{
private String id ;
private SortedMap<String,A> answer;
private String text;
}
public class B extends A{
}
if you feel you need, or just use a boolean field in A
Looking back to the previous question - you could change the xml schema and add some sort of <nextquestion>
tag to answers. The equivalent xml document then would be:
<decision>
<question id="0">
<questionText>What type is your OS?</questionText>
<answer id="0">
<answerText>windows</answerText>
</answer>
<answer id="1">
<answerText>linux</answerText>
</answer>
<answer id="2">
<answerText>mac</answerText>
</answer>
</question>
<question id="1">
<questionText>What are you looking for?</questionText>
<answer id="0">
<answerText>table</answerText>
<!-- NEW TAG HERE -->
<nextquestion refid="3" />
</answer>
<answer id="1">
<answerText>chair</answerText>
</answer>
<answer id="2">
<answerText>bed</answerText>
</answer>
<answer id="3">
<answerText>cloth</answerText>
</answer>
</question>
<!-- ALL QUESTIONS ARE CHILDREN OF ROOT WITH UNIQUE ID -->
<question id="3">
<questionText>Which color table you want?</questionText>
<answer id="0">
<answerText>green</answerText>
</answer>
<answer id="1">
<answerText>black</answerText>
</answer>
<answer id="2">
<answerText>pink</answerText>
</answer>
</question>
</decision>
You may want to use unique ids for the answers too or even reactor the model again if you want to reuse answers for different questions (many-to-many relationship)
And you classes:
public class Question {
private int id;
private String text;
private Set<Answer> answers;
// ...
}
public class Answer {
private int id;
private String text;
private Question nextQuestion;
}
And of course there is a circular dependency but that is absolutely wanted and inherited from the models real-life domain.
try something like:
import java.util.*;
class Question {
Question(int id, String question) {
this.id = id;
this.question = question;
}
static void toString(Question question, StringBuffer sb, int indent) {
for(int i=0;i<indent;i++)
sb.append('\t');
sb.append(question.id).append(' ').append(question.question).append('\n');
for (Map.Entry<Integer, Answer> entry : question.answers.entrySet()) {
Answer answer = entry.getValue();
for(int i=0;i<=indent;i++)
sb.append('\t');
sb.append(entry.getKey()).append(' ').append(answer.answer).append('\n');
if (answer.question != null) {
toString(answer.question, sb, indent+2);
}
}
}
public String toString() {
StringBuffer sb = new StringBuffer();
toString(this,sb, 0);
return sb.toString();
}
int id;
String question;
SortedMap<Integer, Answer> answers = new TreeMap<Integer, Answer>();
}
class Answer {
Answer(int id, String answer) {
this.id = id;
this.answer = answer;
}
final int id;
final String answer;
Question question; // may be null
}
public class Main {
public static void main(String[] args) {
Question q0 = new Question(0, "What are you looking for?");
Answer a0 = new Answer(0, "table");
q0.answers.put(a0.id, a0);
a0.question = new Question(0, "Which color table you want?");
a0.question.answers.put(0, new Answer(0, "green"));
System.out.println(q0);
}
}
精彩评论