Interfaces
Contents
Interfaces#
Note
We use interface to build loosely-coupled, extensible, testable applications.
We should try to keep the coupling or relationship between classes as loosely as possible. Abstract is not enough.
An interface is a type similar to a class, but it includes only methods declarations.
public interface Draggleble {
void drag();
}
Interfaces: what should be down.
Classes: How it should be down.
Tightly-coupled code#
These two classes are tightly-coupled:
public class TaxCalculator {
private double taxableIncome;
public TaxCalculator(double taxableIncome) {
this.taxableIncome = taxableIncome;
}
public double calculateTax() {
return taxableIncome * 0.3;
}
}
public class TaxReport {
private TaxCalculator calculator;
public TaxReport(TaxCalculator calculator) {
this.calculator = calculator;
}
public void show() {
double tax = calculator.calculateTax();
System.out.println(tax);
}
}
Creating an interface#
New Java Class > Interface.
public interface TaxCalculator {
double calculateTax();
}
public class TaxCalculator2023 implements TaxCalculator {
private double taxableIncome;
public TaxCalculator2023(double taxableIncome) {
this.taxableIncome = taxableIncome;
}
@Override
public double calculateTax() {
return taxableIncome * 0.3;
}
}
Dependency injection#
Tip
In reality, most of the time, construct injection is enough.
Constructor injection#
public class TaxReport {
private TaxCalculator calculator;
// working with a interface
// does not know anything about the concrete implementation
public TaxReport(TaxCalculator calculator) {
this.calculator = calculator;
}
public void show() {
double tax = calculator.calculateTax();
System.out.println(tax);
}
}
in Main
:
public class Main {
public static void main(String[] args) {
TaxCalculator2023 calculator = new TaxCalculator2023(100_000);
// inject dependencies
TaxReport report = new TaxReport(calculator);
}
}
Setter injection#
Setter injection allows us to change the dependencies of class.
public void setCalculator(TaxCalculator calculator) {
this.calculator = calculator;
}
in Main
public class Main {
public static void main(String[] args) {
TaxCalculator2023 calculator = new TaxCalculator2023(100_000);
TaxReport report = new TaxReport(calculator);
report.show();
// change dependencies
report.setCalculator(new TaxCalculator2022(100_000));
report.show();
}
}
Method injection#
Injection dependency when we use it.
public class TaxReport {
public void show(TaxCalculator calculator) {
double tax = calculator.calculateTax();
System.out.println(tax);
}
...
}
Interface segregation principal#
Note
Divide big interfaces into smaller ones!
Unlike classes, Java interface can have multiple parents.
Interfaces vs Abstract classes#
Interfaces: Only declarations, no implementation.
Abstract classes: Partially-completed classes, wo that we can share code between a few classes.
Use interfaces when you want to decouple a class from it’s dependencies.
You can easily swap implementation to another.
Program against interfaces: extend your applications with minimal impact.
Unit test: test your classes in isolation.