Abstract Factory

Same as Factory (Creation of objects that conform to the same interface without specifying concrete classes) but to 'families' of objects

Here is a simple way to put together a police unit and a fire unit. Instantiate classes, and then create a unit based on those classes.

  let chief = new FireChief();
  let lt = new FireLieutenant();
  let unitMember = new FireMan();
  let chief2 = new PoliceChief();
  let lt2 = new PoliceLieutenant();
  let unitMember2 = new PoliceUnitMember();

  let PoliceUnit = new Unit(chief2, lt, unitMember);
  let FireMen = new Unit(chief, lt, unitMember);
  
While doing that, it's easy to make mistakes and assign personnel of wrong type to a wrong unit. Abstract factory pattern helps put creation of such units "on rails" and ensure order.
Use Abstract Factory when code needs to work with various families of related products without tight coupling to the actual concrete classes, because they are either unknown at the time or may be expanded in the future. In this example, we're working with factories of first responders. So far there are Police and Firemen. We can also add Medical teams, or other teams that follow the same structure.
Abstract Factory usage requirements:
  1. Explicitly declare interfaces for each distinct piece of the item family (so Chief, Lieutenant, UnitMember)
  2. Make all variants of pieces that follow those interfaces
  3. Declare an abstract Factory (ResponderFactory) with methods to create all items in the family (Chief, Lieutenant, UnitMember)
  4. Declare a separate factory class for each type of ResponderFactory And no mixing and matching!
Let's get into it. First, declare interfaces for the "pieces" that comprise a unit:

  interface Chief {
    command(): string;
  }

  interface Lieutenant {
    manage(): string;
  }

  interface UnitMember {
    doStuff(): string;
  }
  
Then, declare abstract factory interface:

  interface ResponderFactory {
    chief: Chief;
    lt: Lieutenant;
    unitMember: UnitMember;
    makeChief(): Chief;
    makeLieutenant(): Lieutenant;
    makeUnitMember(): UnitMember;
  }
  
Then, declare concrete implementations of the pieces comprising units:

  class FireChief implements Chief {
    command(): string {
      return "Fire Chief: Get those hoses right there right away and gimme water!!";
    }
  }

  class PoliceChief implements Chief {
    command(): string {
      return "Police Chief: I need this solved yesterday!";
    }
  }

  class FireLieutenant implements Lieutenant {
    manage(): string {
      return "Fire Lieutenant: Jeeves, get those two hoses right away! Wooster, turn on the water!";
    }
  }

  class PoliceLieutenant implements Lieutenant {
    manage(): string {
      return "Police Lieutenant: I put my two best men on this case.";
    }
  }

  class FireMan implements UnitMember {
    doStuff(): string {
      return "Fireman: ... (grumble-grumble)";
    }
  }

  class PoliceUnitMember implements UnitMember {
    doStuff(): string {
      return "Police unit member: Pulling out magnifying glass, I'm on the case!";
    }
  }
  
Finally, implement concrete factories creating specific variants of families of products:

  class FiremenUnitFactory implements ResponderFactory {
    chief: Chief;
    lt: Lieutenant;
    unitMember: UnitMember;
    makeChief(): Chief {
      this.chief = new FireChief();
      return this.chief;
    }
    makeLieutenant(): Lieutenant {
      this.lt = new FireLieutenant();
      return this.lt;
    }
    makeUnitMember(): UnitMember {
      this.unitMember = new FireMan();
      return this.unitMember;
    }
    constructor() {
      this.makeChief();
      this.makeLieutenant();
      this.makeUnitMember();
    }
  }

  class PoliceUnitFactory implements ResponderFactory {
    chief: Chief;
    lt: Lieutenant;
    unitMember: UnitMember;

    makeChief(): Chief {
      this.chief = new PoliceChief();
      return this.chief;
    }
    makeLieutenant(): Lieutenant {
      this.lt = new PoliceLieutenant();
      return this.lt;
    }

    makeUnitMember(): UnitMember {
      this.unitMember = new PoliceUnitMember();
      return this.unitMember;
    }
    constructor() {
      this.makeChief();
      this.makeLieutenant();
      this.makeUnitMember();
    }
  }
  
Test:

  let policeUnit = new PoliceUnitFactory();
  console.log(policeUnit.chief.command());
  console.log(policeUnit.lt.manage());
  console.log(policeUnit.unitMember.doStuff());

  let fireUnit = new FiremenUnitFactory();
  console.log(fireUnit.chief.command());
  console.log(fireUnit.lt.manage());
  console.log(fireUnit.unitMember.doStuff());

  /*
  output:
  Police Chief: I need this solved yesterday!
  Police Lieutenant: I put my two best men on this case.
  Police unit member: Pulling out magnifying glass, I''m on the case!
  Fire Chief: Get those hoses right there right away and gimme water!!
  Fire Lieutenant: Jeeves, get those two hoses right away! Wooster, turn on the water!
  Fireman: ... (grumble-grumble)
  */