← Abstract factory lesson
Lab

Abstract factory

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}`);
Screen family
PageStyles
Print family
PageStyles
Observed creation calls Awaiting the choice
At this step
Page renderer

Article

—
Stylesheet

CSS selector

—
Two roles → one export
Export clientArticle not returned yet
Observed HTML preview

Awaiting the rendered article

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.

Play or step to follow the recorded choices.