Fix the overall steps of an algorithm in a base class, and let subclasses fill in just the steps that vary.
Importing CSV, JSON, and XML files all follow the same shape — open file, parse, validate rows, save to database — but each format parses differently. Copy-pasting the whole pipeline per format duplicates the steps that are actually identical.
A base class defines a method that calls a fixed sequence of steps, some implemented directly, others left abstract. Subclasses override only the steps that differ; the order and the shared steps live in one place.
`import()` is defined once, in the base class. Each format subclass only implements `parse()`.
class DataImporter {
import(raw) {
console.log("opening source");
const rows = this.parse(raw); // step that varies — implemented by subclass
const valid = rows.filter((r) => this.validate(r));
console.log(`saving ${valid.length} rows`);
return valid;
}
validate(row) { return row != null; } // shared default, subclasses may override
parse(raw) { throw new Error("parse() must be implemented"); }
}
class CsvImporter extends DataImporter {
parse(raw) { return raw.split("\n").map((line) => line.split(",")); }
}
class JsonImporter extends DataImporter {
parse(raw) { return JSON.parse(raw); }
}
new CsvImporter().import("a,1\nb,2");
new JsonImporter().import('[{"a":1},{"b":2}]');