javainterfacecoupling

When we change the implementation of a method, do we have to recompile dependent classes?


Let's say that we have the following method in class TaxCalculator:

public double calculateTax(double income) {
    return income * 0.3;
}

And we use this method in the Main class like this:

var calculator = new TaxCalculator();
double tax = calculator.calculateTax(100_000);
System.out.println(tax);

If I change the implementation of the calculateTax method to:

public double calculateTax(double income) {
    return income * 0.4;
}

Do I need to recompile both the TaxCalculator class and the Main class?

I know this question sounds very silly, but I heard in a lecture that if we don't use interfaces, every change we make in tightly-coupled code (like the one I showed above) will force us to recompile all the classes that depends on the class we made the change.

And this sounds weird to me, because the Main class doesn't know the implementation of the method we've made the change.

Thanks in advance for any help!


Solution

  • Yeah, that lecturer was just dead wrong. More generally, this is a very outdated notion that used to be a somewhat common refrain, and various lecturers still espouse it:

    The idea that, if you have a class, you make a tandem interface that contains every (public) method in that class; given that the class already occupies the name of the concept, the interface can't be given a good name, and thus, an I is prefixed. You have a class Student and a matching interface IStudent.

    Don't do that. It's a ton of typing, even if you use tools to auto-generate it, everytime you change one you are then forced to change the other, and there is no point to it.

    There are exotic and mostly irrelevant ways in which you get a 'more tight coupling' between a user of the Student class and the Student class code itself vs. having that user use IStudent instead. It sounds like either you or more likely perhaps the lecturer is confused and presumed that this tight coupling implies that any change in Student.java would thus require a recompile.

    Furthermore, if those examples are from the lecture, oh boy. double is absolutely not at all acceptable for financial anything. That should most likely be an int or long, representing cents (or whatever passes for 'atomic monetary unit' for the currency in question; pennies for pounds, satoshis for bitcoin, yen for yen, and so on). In rare cases, BigDecimal. In any case, not, ever, double or float.

    You need to recompile B, where B uses something from A, if:

    And that's essentially it. The interjection of an interface doesn't meaningfully change this list - if that constant is in the interface, the same principle applies (if you change it, you have to recompile users of this constant), and if you change signatures, you'd have to change them in the interface as well, and we're back where we started.

    Adding an interface does have some generally irrelevant bonuses.

    1. Well, you can, but those are a bit clunky, and those would also stop another package in the same project, which was the whole point. You can use hacks to get around this, but if you're willing to use these hacks, you can just make those public, but not actually meant for external consumption non-public and use the same hackery.