Reputation: 3046
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
And the questions raised are
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
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:
Activity
interfaceTimer
class of this typeThen 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
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
f(g(x))
.
f()
and 4 different ways to implement g()
.
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