4.4.1.9–4.4.1.11 - Decomposition, composition and automation (Java)
Break a problem into identifiable tasks, combine procedures and data into useful abstractions, and see how an implemented model can automate a real task. This Java route is incomplete: runnable support pending; source work is written practice.
Procedural decomposition
Procedural decomposition separates a large problem into smaller problems, each with an identifiable task and a clear interface.
Procedural decomposition
Breaking a problem into sub-problems, each accomplishing an identifiable task; a sub-problem may itself be subdivided.
A room-booking tool could have tasks to read a request, check its date and group size, find rooms with sufficient capacity, reject unavailable rooms and present the remaining choices. “Find suitable rooms” can divide further into checking capacity and checking availability. The decomposition is useful because each task has a purpose that can be implemented and checked separately.
Define what each procedure receives, returns and assumes. hasSpace(capacity, booked, requested) could return a Boolean, assuming all three values are non-negative and booked does not exceed capacity. A caller needs this interface, without needing the procedure's internal arithmetic. Distinguish a task from a line of code: “add one” is usually a step inside a meaningful counting task, not a useful top-level decomposition.
Checking smaller components makes defects easier to locate, but the complete system still needs integration tests: a correct capacity check can be called with the wrong room's values. Shared data and side effects can also couple procedures. Returning a result rather than silently changing unrelated state makes the relationship easier to reason about.
Composing procedures and data
Composition builds a larger abstraction by combining existing procedures or data objects into a compound unit.
Procedural decomposition works from a problem down to smaller tasks; composition abstraction works from components up to a compound procedure. These are complementary views. A caller treats the compound procedure as one operation, while its implementation combines the smaller operations in an appropriate order.
public class Main {
static boolean hasSpace(int capacity, int booked, int requested) {
return capacity - booked >= requested;
}
static boolean canBook(int capacity, int booked, int requested,
boolean roomOpen) {
return roomOpen && hasSpace(capacity, booked, requested);
}
}
canBook(30, 22, 8, true) is true; requesting 9 is false. Java's short-circuit && does not call hasSpace when roomOpen is false. The compound procedure has one booking-related purpose; merely placing unrelated procedures in one file is not a useful composition abstraction.
Data composition combines values into meaningful compound data. A room object combines an identifier, capacity and booking count. An array of room objects represents a building's rooms. A tree goes further: each node combines a value with references to child nodes, which are themselves compound objects. A folder tree models parent–child relationships rather than keeping only an unrelated list of names.
Continue this lesson.
You’re previewing NovaLearn without an account. Create a free account to read the rest.
Create free account