is this code a example of circular dependency?
package expr;
import sheet.Sheet
public class AdressExpr implements Expr
{
private Address address;
private Sheet sheet;
public double value(Sheet sheet)
{
return sheet.value(address);
}
}
public interface Expr
{
public double value(Sheet sheet);
}
public class Adress
{
// omissions
}
package sheet;
import expr.Address;
import expr.Expr;
public class Sheet implements SuperSheet
{
private Map <Address, Expr> map;
public double value(Address address)
{
return map.get(Address).value(this);
}
}
public interface SuperSheet
{
public double value(Address address);
}
I know the example is bad programming but doesn't the interface prohibit the circular dependency, due to the value method?
I think it is easier to see in the class diagram. As you can see, there is indeed a circular dependency between Sheet
concrete class and Expr
interface. I wouldn't say it is VERY bad because I consider circular dependency between 2 concrete classes to be the worst... that said, it is certainly not advisable to do so, if possible.
Your Code
So, perhaps one of the ways you might consider refactoring is to have your AddressExpr
to depend on SuperSheet
instead of Sheet
and Expr
to depend on SuperSheet
instead of Sheet
:-
public class AdressExpr implements Expr {
private Address address;
private SuperSheet sheet;
public double value(SuperSheet sheet) {
return sheet.value(address);
}
}
public interface Expr {
public double value(SuperSheet sheet);
}
...
...
... and this will remove any unwanted circular dependencies.
Possible Refactored Code
NOTE: I'm not implying this is the solution. I'm just saying you can certainly look at ways to refactor your code to minimize or remove circular dependencies, because circular dependencies make your code difficult to unit test. Coding against interfaces always help to remove unwanted circular dependencies. It also make your code easier to unit test because you can easily mock objects.
This is a really funky example. I'm going to be pretty verbose about my thought process here because I suspect there's some silly naming going on.
Packages:
sheet
expr
Contents of sheet:
Contents of expr:
Usages in each:
- AddressExpr - Expr, Address, Sheet
- Sheet - SuperSheet, Address
We see that AddressExpr depends on Sheet, which is in the sheet package. One dependency down.
We also see that Sheet depends on Address, in the expr package.
Therefore, you have circular dependency between the sheet and expr packages. (Note: Tools can show this. I did it by hand because your problem was pretty abstract. Look into JDepend)
In addition, I'm not even sure that I've ever heard of a value method. If the compiler can make sense of two-way interface use, it'll work. It has the sense to untangle the mess.
At least on package level. Package sheet
depends on package expr
and vice versa. Based on own experience - I'd refactor this.