user3629892
user3629892

Reputation: 3046

oop: understanding dependencies and coupling between classes

what does it mean exactly, a class knows too much about another one?

Example (adapted from here https://courses.cs.washington.edu/courses/cse331/12au/lectures/08-events.pdf)

class AAA {

    public void method1() {
        //do something
        method2();
    }

    public void method2();
      // do something
    }
}

class BBB {

    private AAA ref = new AAA();

    public void start() {
        while(true) {
            if (something) {
                ref.method1();
            }
        }
    }

}

class Main {

    public static void main(String[] args) {
        BBB ref = new BBB();
        ref.start();
    }

}

In the document it says that

  1. main class depends on BBB
  2. BBB depends on AAA

And the questions raised are

  1. does BBB need to depend on AAA?
  2. Is BBB reusable in a new context?

Regarding 2. - Is it? And if not, why is it not? Why could the dependency on AAA prevent it from being used in a new context? Does context here mean "with a different class"?

And it says that although BBB needs to call the method1(), but it doesnt need to know what that method does. So you should weaken the dependency (loose coupling) by using an interface/abstract class for AAA instead of AAA itself

So new:

class AAA extends AbstractAAA {
// same 
}

class BBB {
    AbstractAAA ref;

    public BBB (AbstractAAA param) {
        this.ref = param;
    }

        public void start() {
        while(true) {
            if (something) {
                ref.method1();
            }
        }
    }
}

class Main {
        BBB ref = new BBB(new AAA());
        ref.start();
}

And now it says that main still depends on BBB and it depends on the constructor of AAA, but BBB is unaffected by the implementation details of AAA.

So dependency means in the broadest sense "Uses an instance of", so I see that therefore Main depends on BBB and on AAA and BBB formerly depended on AAA and now on the abstract class, which is a weaker dependency.

What I dont get is what is the problem exactly with dependencies and implementation details and having to change if another class changes. I get that it is better to use interfaces and abstract classes as parameters of methods and constructors, because you can pass whatever class extends/implements the class/interface. But the thing with the implementation details. When I have a reference of a class (and create a dependency) and call a public method, how am I then dependent on implementation details? Just because I call that method doesnt mean I know whats going on inside it...?

I have looked at other examples here on SO but I still dont really get it...

Upvotes: 4

Views: 845

Answers (2)

beetstra
beetstra

Reputation: 7952

When I have a reference of a class (and create a dependency) and call a public method, how am I then dependent on implementation details? Just because I call that method doesnt mean I know whats going on inside it...?

What's going on inside that method is pretty much determined by the class/implementation you are dependent on. In the example you link to, the Timer class (your AAA) is dependent on the TimeToStretch class (your BBB). And yes, you can change the implementation of TimeToStretch to change the way you stretch. But you cannot change the implementation to drink a soda, that would break (implicit) expectations about what that class does. Other parts of the system may depend on the stretching.

Regarding 2. - Is it? And if not, why is it not? Why could the dependency on AAA prevent it from being used in a new context? Does context here mean "with a different class"?

Yes. If you want to reuse the Timer class to periodically drink a soda, instead of stretch, you can't do that if the Timer class instantiates (and is thus coupled to) the TimeToStretch class. If instead you have:

  • an Activity interface
  • a parameter to the Timer class of this type
  • multiple classes that implement the interface

Then you can use the timer for all these types of activities. Also note the name: the Activity interface is not an AbstractTimeToStretch interface. The function (and thus the name) of the interface is defined by the client using that interface (Timer), not by the (first) implementation.

Hope that helps.

Upvotes: 1

amit
amit

Reputation: 178451

Regarding 2. - Is it? And if not, why is it not? Why could the dependency on AAA prevent it from being used in a new context? Does context here mean "with a different class"?

The problem with the code is the high coupling of BBB and AAA.
BBB is creating an instance of AAA, but that means if you need another variant of AAA, that computes method1() a bit differently (for example, more efficient for some kinds of inputs), you cannot use it, because by creating an instance of BBB - you don't get to choose which implementation of AAA will be used, making this class (BBB) not reuseable.

This is solveable by letting BBB recieve an instance of AAA in the constructor, or an AbstractFactory class, if you need to isolate its instance.

What I dont get is what is the problem exactly with dependencies and implementation details and having to change if another class changes

  1. It avoids reusing existing code without copy-pasting a lot of code, and that's a place where a lot of errors take place.
  2. In addition, assume you are trying to calculate f(g(x)).
    Now, assume you have 3 different "ways" to implement f() and 4 different ways to implement g().
    If your classes are highly coupled, you are going to need a new class for each way of calculation, so you will have to write 3*4=12 classes.
    But if they are decoupled, you are only going to need 3+4=7 classes.
    In big projects, this happens to grow quickly to way too many classes to be able to maintain properly.

When I have a reference of a class (and create a dependency) and call a public method, how am I then dependent on implementation details? Just because I call that method doesnt mean I know whats going on inside it...?

No, but you are dependent on the class, and if that method that you used changes its signature - you are going to need to change your code as well, so if a change in class A, is making you to change your class as well, you are dependent on class A.

Upvotes: 4

Related Questions