Structural
How objects fit together: wrapping, adapting and composing them.
Structural problems are about the shape of the code rather than any single algorithm. A vendor library with an awkward interface leaks into every class, a tree of items is handled with different code for leaves and branches, or every combination of features gets its own subclass.
The fix is usually to put a well-chosen object in between: one that translates an interface, wraps another object to add a feature, treats a group like a single item, or stands in for something expensive until it is really needed.
You'll recognise it when
- Third-party types appear in method signatures all over your domain code.
- Class names combine two ideas (EncryptedCompressedFile, RedLargeButton).
- The same recursion over a tree is hand-written in several places.
- Callers must make several calls in a fixed order to do one thing.
Example
A music player shows lyrics from a vendor whose API uses its own track codes and returns raw text.
class NowPlayingScreen {
String lyrics(Song song) {
VendorLyricsApi api = new VendorLyricsApi();
String raw = api.fetchLyr("TRK-" + song.isrc(), "en-IN");
return raw.replace("\\n", "\n").trim();
}
}
// ...and the same three lines again in the karaoke screeninterface Lyrics {
String forSong(Song song);
}
class VendorLyrics implements Lyrics {
private final VendorLyricsApi api = new VendorLyricsApi();
public String forSong(Song song) {
return api.fetchLyr("TRK-" + song.isrc(), "en-IN").replace("\\n", "\n").trim();
}
}
class NowPlayingScreen {
private final Lyrics lyrics;
NowPlayingScreen(Lyrics lyrics) { this.lyrics = lyrics; }
String lyrics(Song song) { return lyrics.forSong(song); }
}Why it's better: Only one class knows the vendor exists. Switching vendors, or using a fake in tests, means writing one new class instead of editing every screen.
Ideas you'll practise
Problems 17
- ST-12A Coffee Class for Every Add-On MixL1EasyFREE
- ST-01Three Payment Gateways, Three APIsL1EasyComing soon
- ST-02Legacy XML Service in a JSON WorldL1MediumComing soon
- ST-03The Maps SDK Leaks EverywhereL1MediumComing soon
- ST-04Adapter of an Adapter of an AdapterL3MediumComing soon
- ST-05A Shape Class for Every Output FormatL1MediumComing soon
- ST-07A Remote for Every TVL1HardComing soon
- ST-08Files and Folders Treated DifferentlyL1EasyComing soon
- ST-09Org Chart Salary TotalsL1MediumComing soon
- ST-13Streams With Every CombinationL1MediumComing soon
- ST-14Logging Pasted Into Every MethodL1MediumComing soon
- ST-15Decorators That Must Stop the ChainL2MediumComing soon
- ST-16Placing an Order Takes Seven CallsL1EasyComing soon
- ST-18The Facade That Ate the CodebaseL2MediumComing soon
- ST-21Images Loaded Before Anyone LooksL1MediumComing soon
- ST-22Permission Checks Inside Business LogicL1MediumComing soon
- ST-23Caching Tangled Into a Slow API ClientL1MediumComing soon