does this form a circular dependency?

46 Views Asked by At

I am developing a chess program, currently refactoring some classes, and was wondering if the followings are creating a circular dependency.

Class A, depends on class B and C, and class C depends on class B.

A:

public class MoveValidatorHandler  {
    private PositionHandler positionHandler;
    private CheckMovementHandler checkMovementHandler;

    public MoveValidatorHandler(PositionHandler positionHandler,CheckMovementHandler checkMovementHandler){
        this.positionHandler = positionHandler;
        this.checkMovementHandler = checkMovementHandler;
    }

B:

public class PositionHandler {
// this one only contains methods
}

C:

public class CheckMovementHandler {
   
    private PositionHandler positionHandler;

    public CheckMovementHandler(PositionHandler positionHandler){
        this.positionHandler = positionHandler;
    }
2

There are 2 best solutions below

1
Minko_Minkov On

For cases like these, it makes it a lot easier when you draw an image of a directed graph, and have a directed line from A to B if A depends on B :).

If you can follow the arrows, and find a loop, then there is a circular dependency.

Class dependency graph

1
rzwitserloot On

No.

You can:

  • Compile B.java on its own without A or C known to the compiler. This will work.
  • You can then compile C.java on its own, putting the result of the previous step on the classpath. The system does not need to know about A.java or A.class at all.
  • You can then compile A.java on its own, putting the result of the previous 2 steps on the classpath.

Whenever you can build a chain like that, it's not circular. Circular is this:

// file A.java
class A {
  B something;
}

// file B.java
class B {
  A something;
}

Here, you can't compile A without having B available. You also can't compile B without having A available. The only way you can possibly compile this code is by compiling them both in one go, which javac can do just fine: javac *.java will take care of it.

There are reasons to try to avoid circular dependencies, but between source files like this, it mostly does not matter, and tons of java projects do have such circular dependencies. javac doesn't care, you just have to compile both of them at once. Which just about every java buildsystem already does (build systems compile your whole stack in one go, they don't compile file for file, invoking javac each and every time).

It's, essentially, 'style advice'. And like all style advice, all hard rules are stupid (and probably even that hard rule is stupid). Style is not that easy and rules are conflicting. It is silly to blindly apply style advice you don't understand, and without applying a modicum of judgement. After all, there's so much style advice out there, it is simply impossible to write anything but the most academically simple of programmers without running into a scenario where 2 seemingly relevant bits of advice are mutually exclusive and you are forced to violate one of them.

How could you possibly know which one to apply? This counts double if you are incapable of knowing which of the many many style advice you're operating under is even relevant to the situation at hand.