Design Patterns: Abstract Factory

Creates an instance of several families of classes..
TypeScript:
Compile code as follow:
tsc --target es5  .\abstract-factory.ts
node abstract-factory.js
abstract class AbstractFactoryAccount {
  abstract validate(): boolean;
  abstract calculate(): number;
}

abstract class AbstractFactorySales {
  abstract validate(): boolean;
  abstract calculate(): number;
}

class ProductSales extends AbstractFactorySales {
  constructor(value: String) {
    super();
    console.log(value);
  }
  validate(): boolean {
    return true;
  };
  calculate(): number {
    return 1200.77;
  };
}

class ProductAccount extends AbstractFactoryAccount {
  constructor(value: String) {
    super();
    console.log(value);
  }
  validate(): boolean {
    return true;
  };
  calculate(): number {
    return 2000.88;
  };
}

abstract class AbstractFactory {
  abstract createProductA(): AbstractFactorySales;
  abstract createProductB(): AbstractFactoryAccount;
}

class UnitedStatesFactory extends AbstractFactory {
  createProductA(): ProductSales {
    return new ProductSales('ProductSales made in the United States of America');
  }

  createProductB(): ProductAccount {
    return new ProductAccount('ProductAccount made in the United States of America');
  }
}

class CanadaFactory extends AbstractFactory {
  createProductA(): ProductSales {
    return new ProductSales('ProductSales made in Canada');
  }

  createProductB(): ProductAccount {
    return new ProductAccount('ProductAccount made in Canada');
  }
}

(function main() {
  const usFactory = new UnitedStatesFactory();
  console.log(usFactory.createProductA());
  console.log(usFactory.createProductB());

  const caFactory = new CanadaFactory();
  console.log(caFactory.createProductA());
  console.log(caFactory.createProductB());
})();

Abstract Factory TypeScript inspired from Head First Design Pattern book
class PizzaTestDrive {
      
      public Main(args: string[]) {
          let nyStore: PizzaStore = new NewYorkPizzaStore();
          let chStore: PizzaStore = new ChicagoPizzaStore();

          console.log("");
          console.log("");

          nyStore.OrderPizza("Ethan", "cheese");
          chStore.OrderPizza("Joel", "cheese");

          nyStore.OrderPizza("Ethan", "clam");
          chStore.OrderPizza("Joel", "clam");

          nyStore.OrderPizza("Ethan", "pepperoni");
          chStore.OrderPizza("Joel", "pepperoni");

          nyStore.OrderPizza("Ethan", "veggie");
          chStore.OrderPizza("Joel", "veggie");

          console.log("");
          console.log("");
      }
  }
  
  export interface IPizzaIngredientFactory {      
      CreateDough(): IDough;      
      CreateSauce(): ISauce;      
      CreateCheese(): ICheese;      
      CreateVeggies(): IVeggies[];      
      CreatePepperoni(): IPepperoni;      
      CreateClam(): IClams;
  }
  
  export class NewYorkPizzaIngredientFactory implements IPizzaIngredientFactory {      
      public CreateDough(): IDough {
          return new ThinCrustDough();
      }
      
      public CreateSauce(): ISauce {
          return new MarinaraSauce();
      }
      
      public CreateCheese(): ICheese {
          return new ReggianoCheese();
      }
      
      public CreateVeggies(): IVeggies[] {
          let veggies: IVeggies[] = [
                  new Garlic(),
                  new Onion(),
                  new Mushroom(),
                  new RedPepper()];
          return veggies;
      }
      
      public CreatePepperoni(): IPepperoni {
          return new SlicedPepperoni();
      }
      
      public CreateClam(): IClams {
          return new FreshClams();
      }
  }
  
  export class ChicagoPizzaIngredientFactory implements IPizzaIngredientFactory {      
      public CreateDough(): IDough {
          return new ThickCrustDough();
      }
      
      public CreateSauce(): ISauce {
          return new PlumTomatoSauce();
      }
      
      public CreateCheese(): ICheese {
          return new MozzarellaCheese();
      }
      
      public CreateVeggies(): IVeggies[] {
          let veggies: IVeggies[] = [
                  new BlackOlives(),
                  new Spinach(),
                  new Eggplant()];
          return veggies;
      }
      
      public CreatePepperoni(): IPepperoni {
          return new SlicedPepperoni();
      }
      
      public CreateClam(): IClams {
          return new FrozenClams();
      }
  }
  
  export abstract class PizzaStore {
      
      public OrderPizza(nameOfPersonOrderingPizza: string, type: string): Pizza {
          let pizza: Pizza = this.CreatePizza(type);

          console.log(nameOfPersonOrderingPizza + " ordered a \"" + pizza.Name + "\"");
          console.log("--- Making a " + pizza.Name + " ---");
          
          pizza.Prepare();                   
          pizza.Bake();
          pizza.Cut();
          pizza.Box();

          console.log("=============================");
          console.log("");

          return pizza;
      }
      
      public abstract CreatePizza(item: string): Pizza;
  }
  
  export class NewYorkPizzaStore extends PizzaStore {
      
      public /* override */  CreatePizza(item: string): Pizza {
          let pizza: Pizza = null;
          let ingredientFactory: IPizzaIngredientFactory = new NewYorkPizzaIngredientFactory();
          switch (item) {
              case "cheese":
                  pizza = new CheesePizza(ingredientFactory);
                  pizza.Name = "New York Style Cheese Pizza";
                  break;
              case "veggie":
                  pizza = new VeggiePizza(ingredientFactory);
                  pizza.Name = "New York Style Veggie Pizza";
                  break;
              case "clam":
                  pizza = new ClamPizza(ingredientFactory);
                  pizza.Name = "New York Style Clam Pizza";
                  break;
              case "pepperoni":
                  pizza = new PepperoniPizza(ingredientFactory);
                  pizza.Name = "New York Style Pepperoni Pizza";
                  break;
          }
          
          return pizza;
      }
  }
  
  export class ChicagoPizzaStore extends PizzaStore {      
      //  Factory method implementation
      public /* override */ CreatePizza(item: string): Pizza {
          let pizza: Pizza = null;
          let ingredientFactory: IPizzaIngredientFactory = new ChicagoPizzaIngredientFactory();
          switch (item) {
              case "cheese":
                  pizza = new CheesePizza(ingredientFactory);
                  pizza.Name = "Chicago Style Cheese Pizza";
                  break;
              case "veggie":
                  pizza = new VeggiePizza(ingredientFactory);
                  pizza.Name = "Chicago Style Veggie Pizza";
                  break;
              case "clam":
                  pizza = new ClamPizza(ingredientFactory);
                  pizza.Name = "Chicago Style Clam Pizza";
                  break;
              case "pepperoni":
                  pizza = new PepperoniPizza(ingredientFactory);
                  pizza.Name = "Chicago Style Pepperoni Pizza";
                  break;
          }
          
          return pizza;
      }
  }
  
  export abstract class Pizza {      
      protected dough: IDough;      
      protected sauce: ISauce;      
      protected veggies: IVeggies[];      
      protected cheese: ICheese;      
      protected pepperoni: IPepperoni;      
      protected clam: IClams;      
      private name: string;
      
      public abstract Prepare();
      
      public Bake() {
          console.log("Bake for 25 minutes at 350");
      }
      
      public Cut() {
          console.log("Cutting the pizza into diagonal slices");
      }
      
      public Box() {
          console.log("Place pizza in official Pizzastore box");
      }
      
      public get Name(): string {
          return this.name;
      }
      public set Name(value: string)  {
          this.name = value;
      }
      
      public HowToPrepareIngredients(): void {
          let result: string;

          console.log("-----------------------------");      
       
          if (this.dough != null) {
              result = this.dough.ToString();
              console.log(result);
          }
          
          if (this.sauce != null) {
            result = this.sauce.ToString();
            console.log(result);
          }
          
          if (this.cheese != null) {
              result = this.cheese.ToString();
              console.log(result);
          }
          
          if (this.veggies != null) {
              result = "";
              for (let i: number = 0; i < this.veggies.length; i++) {
                  result += this.veggies[i].ToString();
                  if (i < this.veggies.length - 1) {
                    result += ", ";
                  }                  
              }
              if (result) {
                console.log(result);
              }             
          }
          
          if (this.clam != null) {
            result = this.clam.ToString();
            console.log(result);
          }
          
          if (this.pepperoni != null) {
              result = this.pepperoni.ToString();
              console.log(result);
          }

          console.log("-----------------------------");  
      }
  }
  
  export class ClamPizza extends Pizza {
      
      private _ingredientFactory: IPizzaIngredientFactory;
      
      public constructor (ingredientFactory: IPizzaIngredientFactory) {
          super();
          this._ingredientFactory = ingredientFactory;
      }
      
      public /* override */ Prepare() {          
          this.dough = this._ingredientFactory.CreateDough();
          this.sauce = this._ingredientFactory.CreateSauce();
          this.cheese = this._ingredientFactory.CreateCheese();
          this.clam = this._ingredientFactory.CreateClam();
          this.HowToPrepareIngredients();
          console.log("Preparing " + this.Name);
      }
  }
  
  export class CheesePizza extends Pizza {
      
      private _ingredientFactory: IPizzaIngredientFactory;
      
      public constructor (ingredientFactory: IPizzaIngredientFactory) {
          super();
          this._ingredientFactory = ingredientFactory;
      }
      
      public /* override */  Prepare() {          
          this.dough = this._ingredientFactory.CreateDough();
          this.sauce = this._ingredientFactory.CreateSauce();
          this.cheese = this._ingredientFactory.CreateCheese();
          this.HowToPrepareIngredients();
          console.log("Preparing " + this.Name);
      }
  }
  
  export class PepperoniPizza extends Pizza {
      
      private _ingredientFactory: IPizzaIngredientFactory;
      
      public constructor (ingredientFactory: IPizzaIngredientFactory) {
          super();
          this._ingredientFactory = ingredientFactory;
      }
      
      public /* override */  Prepare() {          
          this.dough = this._ingredientFactory.CreateDough();
          this.sauce = this._ingredientFactory.CreateSauce();
          this.cheese = this._ingredientFactory.CreateCheese();
          this.veggies = this._ingredientFactory.CreateVeggies();
          this.pepperoni = this._ingredientFactory.CreatePepperoni();
          this.HowToPrepareIngredients();
          console.log("Preparing " + this.Name);
      }
  }
  
  export class VeggiePizza extends Pizza {
      
      private _ingredientFactory: IPizzaIngredientFactory;
      
      public constructor (ingredientFactory: IPizzaIngredientFactory) {
          super();
          this._ingredientFactory = ingredientFactory;
      }
      
      public /* override */  Prepare() {          
          this.dough = this._ingredientFactory.CreateDough();
          this.sauce = this._ingredientFactory.CreateSauce();
          this.cheese = this._ingredientFactory.CreateCheese();
          this.veggies = this._ingredientFactory.CreateVeggies();
          this.HowToPrepareIngredients();
          console.log("Preparing " + this.Name);
      }
  }
  
  export class ThinCrustDough implements IDough {      
      public ToString(): string {
          return "Thin Crust Dough";
      }
  }
  
  export class ThickCrustDough implements IDough {      
      public ToString(): string {
          return "ThickCrust style extra thick crust dough";
      }
  }
  
  export class Spinach implements IVeggies {      
      public ToString(): string {
          return "Spinach";
      }
  }
  
  export class SlicedPepperoni implements IPepperoni {      
      public ToString(): string {
          return "Sliced Pepperoni";
      }
  }
  
  export interface ISauce {      
      ToString(): string;
  }
  
  export interface IDough {      
      ToString(): string;
  }
  
  export interface IClams {      
      ToString(): string;
  }
  
  export interface IVeggies {      
      ToString(): string;
  }
  
  export interface ICheese {      
      ToString(): string;
  }
  
  export interface IPepperoni {      
      ToString(): string;
  }
  
  export class Garlic implements IVeggies {      
      public  ToString(): string {
          return "Garlic";
      }
  }
  
  export class Onion implements IVeggies {      
      public  ToString(): string {
          return "Onion";
      }
  }
  
  export class Mushroom implements IVeggies {      
      public  ToString(): string {
          return "Mushrooms";
      }
  }
  
  export class Eggplant implements IVeggies {      
      public  ToString(): string {
          return "Eggplant";
      }
  }
  
  export class BlackOlives implements IVeggies {      
      public  ToString(): string {
          return "Black Olives";
      }
  }
  
  export class RedPepper implements IVeggies {      
      public  ToString(): string {
          return "Red Pepper";
      }
  }
  
  export class PlumTomatoSauce implements ISauce {      
      public  ToString(): string {
          return "Tomato sauce with plum tomatoes";
      }
  }
  
  export class MarinaraSauce implements ISauce {      
      public  ToString(): string {
          return "Marinara Sauce";
      }
  }
  
  export class FreshClams implements IClams {      
      public  ToString(): string {
          return "Fresh Clams from Long Island Sound";
      }
  }
  
  export class FrozenClams implements IClams {      
      public  ToString(): string {
          return "Frozen Clams from Chesapeake Bay";
      }
  }
  
  export class ParmesanCheese implements ICheese {      
      public  ToString(): string {
          return "Shredded Parmesan";
      }
  }
  
  export class MozzarellaCheese implements ICheese {      
      public  ToString(): string {
          return "Shredded Mozzarella";
      }
  }
  
  export class ReggianoCheese implements ICheese {      
      public  ToString(): string {
          return "Reggiano Cheese";
      }
  }


let p = new PizzaTestDrive();
p.Main(null);