Page renderer
Article
—
interface PageRenderer {
render(title: string): string;
}
interface Stylesheet {
css(): string;
}
// The abstract factory: one contract that creates both product roles.
interface ExportFactory {
createPage(): PageRenderer;
createStyles(): Stylesheet;
}
const makePage = (className: string): PageRenderer => ({
render: (title) => `<article class="${className}"><h1>${title}</h1></article>`,
});
const makeStyles = (className: string, font: string): Stylesheet => ({
css: () => `.${className} { font-family: ${font} }`,
});
// Two concrete families. Each creates a page and a stylesheet that agree.
const screenFactory: ExportFactory = {
createPage: () => makePage('screen-page'),
createStyles: () => makeStyles('screen-page', 'sans-serif'),
};
const printFactory: ExportFactory = {
createPage: () => makePage('print-page'),
createStyles: () => makeStyles('print-page', 'serif'),
};
// The client asks one family for both roles. It never names screen or print.
function exportDocument(factory: ExportFactory, title: string): string {
const page = factory.createPage();
const styles = factory.createStyles();
return `<style>${styles.css()}</style>${page.render(title)}`;
}
// Two callers, each choosing a family once.
const editor = exportDocument(screenFactory, 'Release notes');
const report = exportDocument(printFactory, 'Release notes');
console.log(`editor: ${editor}`);
console.log(`report: ${report}`);
The class and selector appear as the products run.
Families are the lesson map. Values and highlighted calls follow this step.Completed exports remain for comparison.