Java interfaces and composition

Depend on a contract and inject a collaborating object.

Java
interface Formatter {
    String format(String text);
}
class BracketFormatter implements Formatter {
    public String format(String text) { return "[" + text + "]"; }
}
class Report {
    private final Formatter formatter;
    Report(Formatter formatter) { this.formatter = formatter; }
    String render() { return formatter.format("Ready"); }
}
class Main {
    public static void main(String[] args) {
        Report report = new Report(new BracketFormatter());
        System.out.println(report.render());
    }
}
Output
[Ready]

Explanation

An interface declares operations that implementing classes provide. A Report receives a Formatter rather than constructing one hard-coded implementation internally.

Report has a formatter; it is not a formatter. This composition makes it possible to change formatting behavior while keeping report logic unchanged.

Explore the dry run
Guided walkthroughReady
1interface Formatter {
2 String format(String text);
3}
4class BracketFormatter implements Formatter {
5 public String format(String text) { return "[" + text + "]"; }
6}
7class Report {
8 private final Formatter formatter;
9 Report(Formatter formatter) { this.formatter = formatter; }
10 String render() { return formatter.format("Ready"); }
11}
12class Main {
13 public static void main(String[] args) {
14 Report report = new Report(new BracketFormatter());
15 System.out.println(report.render());
16 }
17}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Construct and inject a formatter.report.formatter = BracketFormatter
—
Delegate through the interface.text = Ready
—
The implementation wraps the text.return = [Ready]
—
Print the rendered result.return = [Ready]
[Ready]

Cost and common mistakes

O(n) time and space to construct formatted text of length n.

  • A final reference cannot be reassigned, but does not automatically make the referenced object immutable.
  • This example expects a non-null formatter; production constructors should enforce required dependencies.

Try it yourself

Implement a formatter that adds parentheses.

Reveal answer and reasoning

Return '(' + text + ')' as a string expression. Inject it to produce (Ready).

Further reading