Factory Method Pattern

Definition

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Explanation

Creating an object often requires complex processes not appropriate to include within a composing object. The object’s creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object’s concerns. The factory method design pattern handles these problems by defining a separate method for creating the objects, which subclasses can then override to specify the derived type of product that will be created.

The factory method pattern relies on inheritance, as object creation is delegated to subclasses that implement the factory method to create objects.

Screencast

TypeScript Code

module FactoryMethod {
    class Page {
        private _type: string;
        constructor(type: string) {
            this._type = type;
        }

        public get Type(): string {
            return this._type;
        }
    }

    class SkillsPage extends Page {
        constructor() {
            super("SkillsPage");
        }
    }

    class EducationPage extends Page {
        constructor() {
            super("EducationPage");
        }
    }

    class ExperiencePage extends Page {
        constructor() {
            super("ExperiencePage");
        }
    }

    class IntroductionPage extends Page {
        constructor() {
            super("IntroductionPage");
        }
    }

    class ResultsPage extends Page {
        constructor() {
            super("ResultsPage");
        }
    }

    class ConclusionPage extends Page {
        constructor() {
            super("ConclusionPage");
        }
    }

    class SummaryPage extends Page {
        constructor() {
            super("SummaryPage");
        }
    }

    class BibliographyPage extends Page {
        constructor() {
            super("BibliographyPage");
        }
    }

    class PageFactory {
        private _pages: Array = new Array();
        private _type: string;

        constructor(type: string) {
            this._type = type;
            this.createPages();
        }

        public get type(): string {
            return this._type;
        }
        public get pages(): Array {
            return this._pages;
        }

        public createPages(): void {
            throw new Error("Method not implemented");
        }
    }

    class Resume extends PageFactory {
        constructor() {
            super("Resume");
        }

        public createPages(): void {
            this.pages.push(new SkillsPage());
            this.pages.push(new EducationPage());
            this.pages.push(new ExperiencePage());
        }
    }

    class Report extends PageFactory {
        constructor() {
            super("Report");
        }

        public createPages(): void {
            this.pages.push(new IntroductionPage());
            this.pages.push(new ResultsPage());
            this.pages.push(new ConclusionPage());
            this.pages.push(new SummaryPage());
            this.pages.push(new BibliographyPage());
        }
    }

    window.addEventListener("load", function () {
        var factories: Array = new Array(new Resume(), new Report());

        factories.forEach((factory: PageFactory) => {
            Output.WriteLine("The " + factory.type + " contains the following pages:");
            factory.pages.forEach((page: Page) => {
                Output.WriteLine("--" + page.Type);
            });
        });
    });
}

Output