Template Method: Report Generator

Problem

A report always has three steps in the same order: header, row and footer. The base class has a method generate(name) that fixes this order, and the subclasses fill in the steps. CSV report: header id,name; row 1,<name>; footer end. HTML report: header <table>; row <tr><name></tr>; footer </table>. Text report: header # report; row - <name>; footer --. Every input line is: kind name. Print header: ... | row: ... | footer: ... for each line.

Constraints

  • 1 <= lines <= 10^4
  • names have no spaces

Examples

Input

csv amit

Output

header: id,name | row: 1,amit | footer: end

Solutions

Best approachTime O(n)Space O(n)

The Template Method pattern keeps the fixed order of an algorithm in the base class and lets subclasses change only the steps. In Java the template method is marked final, so a subclass cannot break the order by mistake. The pattern is the reason frameworks call your code ('do not call us, we call you').

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several lines.
 * Output  : One report line per input line.
 * Approach: Subclasses fill in the steps.
 * Time    : O(n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The template method generate() is final: it fixes the order of the steps. The subclasses cannot change it.
        static abstract class Report {
            final String generate(String name) {
                return "header: " + header() + " | row: " + row(name) + " | footer: " + footer();
            }

            abstract String header();

            abstract String row(String name);

            abstract String footer();
        }

        // Step 2: Each subclass fills in the steps (the "hooks") for its own format.
        static class CsvReport extends Report {
            String header() {
                return "id,name";
            }

            String row(String name) {
                return "1," + name;
            }

            String footer() {
                return "end";
            }
        }

        static class HtmlReport extends Report {
            String header() {
                return "<table>";
            }

            String row(String name) {
                return "<tr>" + name + "</tr>";
            }

            String footer() {
                return "</table>";
            }
        }

        static class TextReport extends Report {
            String header() {
                return "# report";
            }

            String row(String name) {
                return "- " + name;
            }

            String footer() {
                return "--";
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            Report report = part[0].equals("csv") ? new CsvReport() : part[0].equals("html") ? new HtmlReport() : new TextReport();
            // Step 3: The caller only calls the template method.
            output[i] = report.generate(part[1]);
        }
        return output;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (1)
  1. Why is generate() marked final in Java?