Skip to content

Template Method ​

Template Method defines an operation's fixed sequence in a base type and lets subclasses customize selected steps. It suits an established class hierarchy; composition is usually preferable for new, highly variable systems.

When it helps in iOS ​

An export feature must validate a document, render it, and write a file. PDF and text exports have different rendering but the same lifecycle.

Original example: export skeleton ​

swift
import Foundation

enum ExportError: Error { case emptyDocument }

class DocumentExporter {
    final func export(_ text: String, to directory: URL) throws -> URL {
        guard !text.isEmpty else { throw ExportError.emptyDocument }
        let data = try render(text)
        let url = directory.appendingPathComponent("export").appendingPathExtension(fileExtension)
        try data.write(to: url, options: .atomic)
        return url
    }

    var fileExtension: String { fatalError("Override fileExtension") }
    func render(_ text: String) throws -> Data { fatalError("Override render") }
}

final class TextExporter: DocumentExporter {
    override var fileExtension: String { "txt" }
    override func render(_ text: String) throws -> Data {
        Data(text.utf8)
    }
}

The final export method fixes validation and atomic writing. Subclasses supply only the variable rendering steps.

Production decisions ​

Prefer an abstract protocol plus injected renderer if clients need many combinations or if subclass overrides could violate invariants. Give each export a unique filename in a real app to avoid overwriting previous files. For PDFs, use a renderer that respects page size, fonts, and accessibility.

Separate invariant steps from variable steps ​

DocumentExporter.export is final, so subclasses cannot reorder validation, rendering, and atomic writing. render(_:) and fileExtension are the overridable hooks. TextExporter provides a concrete rendering operation while inheriting the common export lifecycle. This is the Template Method: a fixed algorithm skeleton with selected steps supplied by subclasses. The hooks use fatalError in the educational base class because Swift does not have abstract class methods.

From example to iOS document sharing ​

A document screen chooses an exporter, asks it to write into a temporary or app-owned directory, then presents the resulting URL in UIActivityViewController or a document picker. Production code should choose a unique filename, clean old temporary files, and render heavy PDF work off the main actor. Validate the document and file destination before writing. Keep file coordination and security-scoped URL handling in an appropriate platform layer.

Failure modes and verification ​

Test that empty text is rejected before rendering, that write errors propagate, and that each exporter uses the right extension and bytes. A new subclass can forget a hook and crash at fatalError; a protocol with an injected renderer makes missing requirements a compile-time error. Prefer composition for new systems with several independent variations. Use Template Method when a stable inherited workflow already exists and the variation points are few.

All patterns

Released under the MIT License.