We can generate multiple factories using the Abstract factory pattern. To understand the Abstract factory pattern, make sure that you understand the Factory pattern before the Abstract Factory pattern.
NOTES
Abstract factory pattern works as a factory of the Factory pattern, so before learning the details of the Abstract factory pattern make sure to have a clear idea about the Factory pattern.
NOTES
In this article, we discuss the implementation of the Abstract Factory Pattern in TypeScript.
See the Abstract Factory in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Abstract Factory Pattern-
Implementation
Use the following steps for the implementation-
Here is a simple Abstract factory implementation in TypeScript. This is not any specific example, just demo/sample code.
// --- Item interface start ---
interface ItemInterface {
operation1(): void;
operation2(): void;
}
// --- Item interface end ---
// --- Type1 item classes start ---
class Type1Item1 implements ItemInterface {
operation1(): void {
console.log("Type1Item1: executing operation 1");
}
operation2(): void {
console.log("Type1Item1: executing operation 2");
}
}
class Type1Item2 implements ItemInterface {
operation1(): void {
console.log("Type1Item2: executing operation 1");
}
operation2(): void {
console.log("Type1Item2: executing operation 2");
}
}
// --- Type1 item classes end ---
// --- Type2 item classes start ---
class Type2Item1 implements ItemInterface {
operation1(): void {
console.log("Type2Item1: executing operation 1");
}
operation2(): void {
console.log("Type2Item1: executing operation 2");
}
}
class Type2Item2 implements ItemInterface {
operation1(): void {
console.log("Type2Item2: executing operation 1");
}
operation2(): void {
console.log("Type2Item2: executing operation 2");
}
}
// --- Type2 item classes end ---
// --- Factory interface start ---
interface FactoryInterface {
getItem(type: string): (ItemInterface | null);
}
// --- Factory interface end ---
// --- Factory classes start ---
class Type1Factory implements FactoryInterface {
getItem(itemIdentifier: string): (ItemInterface | null) {
if (itemIdentifier.toLowerCase() === "item1") {
return new Type1Item1();
}
if (itemIdentifier.toLowerCase() === "item2") {
return new Type1Item2();
}
return null;
}
}
class Type2Factory implements FactoryInterface {
getItem(itemIdentifier: string): (ItemInterface | null) {
if (itemIdentifier.toLowerCase() === "item1") {
return new Type2Item1();
}
if (itemIdentifier.toLowerCase() === "item2") {
return new Type2Item2();
}
return null;
}
}
// --- Factory classes end ---
// --- Facotyr producer start ---
class FactoryProducer {
static getFactory(type: number): (FactoryInterface | null) {
if (type == 1) {
return new Type1Factory();
}
if (type == 2) {
return new Type2Factory();
}
return null;
}
}
// --- Factory producer end ---
// --- Demo start ---
const factory1 = FactoryProducer.getFactory(1);
const item1 = factory1?.getItem("item1");
item1?.operation1();
item1?.operation2();
const factory2 = FactoryProducer.getFactory(2);
const item2 = factory2?.getItem("item1");
item2?.operation1();
item2?.operation2();
const item3 = factory2?.getItem("item2");
item3?.operation1();
item3?.operation2();
// --- Demo end ---
TypeScriptThe above code will generate the following output:
Type1Item1: executing operation 1
Type1Item1: executing operation 2
Type2Item1: executing operation 1
Type2Item1: executing operation 2
Type2Item2: executing operation 1
Type2Item2: executing operation 2
PlaintextExamples
Let’s look at a few examples of Abstract factory pattern implementation in TypeScript.
Example #1: Transport
In this example, we have a few item classes which represent different vehicles. Some of the vehicles are 2 wheelers and some are 4 wheelers.
We are going to implement 2 factories for those 2 types of vehicles. Then we will implement a producer that will combine those 2 types of factories.
Transport Interface [Item Interface]
// transport.ts
interface Transport {
start(): void;
stop(): void;
repair(): void;
}
export default Transport;
TypeScriptBicycle Class [Item Class]
// bicycle.ts
import Transport from "./transport";
class Bicycle implements Transport {
start(): void {
console.log("Bicycle Started");
}
stop(): void {
console.log("Bicycle Stopped");
}
repair(): void {
console.log("Bicycle Repair");
}
}
export default Bicycle;
TypeScriptMotorcycle Class [Item Class]
// motorcycle.ts
import Transport from "./transport";
class Motorcycle implements Transport {
start(): void {
console.log("Motorcycle Started");
}
stop(): void {
console.log("Motorcycle Stopped");
}
repair(): void {
console.log("Motorcycle Repair");
}
}
export default Motorcycle;
TypeScriptCar Class [Item Class]
// car.ts
import Transport from "./transport";
class Car implements Transport {
start(): void {
console.log("Car Started");
}
stop(): void {
console.log("Car Stopped");
}
repair(): void {
console.log("Car Repair");
}
}
export default Car;
TypeScriptTruck Class [Item Class]
// truck.ts
import Transport from "./transport";
class Truck implements Transport {
start(): void {
console.log("Truck Started");
}
stop(): void {
console.log("Truck Stopped");
}
repair(): void {
console.log("Truck Repair");
}
}
export default Truck;
TypeScriptAbstract Transport Factory Interface [Factory Interface]
This can be an abstract class, if required.
// abstract-transport-factory.ts
import Transport from "./transport";
interface AbstractTransportFactory {
getTransport(type: string): (Transport | null);
}
export default AbstractTransportFactory;
TypeScriptTwo-Wheel Transport Factory Class [Factory Class]
// two-wheel-transport-factory.ts
import AbstractTransportFactory from "./abstract-transport-factory";
import Bicycle from "./bicycle";
import Motorcycle from "./motorcycle";
import Transport from "./transport";
class TwoWheelTransportFactory implements AbstractTransportFactory {
getTransport(type: string): (Transport | null) {
if (type.toLowerCase() === "bicycle") {
return new Bicycle();
}
if (type.toLowerCase() === "motorcycle") {
return new Motorcycle();
}
return null;
}
}
export default TwoWheelTransportFactory;
TypeScriptFour-Wheel Transport Factory Class [Factory Class]
// four-wheel-transport-factory.ts
import AbstractTransportFactory from "./abstract-transport-factory";
import Car from "./car";
import Transport from "./transport";
import Truck from "./truck";
class FourWheelTransportFactory implements AbstractTransportFactory {
getTransport(type: string): (Transport | null) {
if (type.toLowerCase() === "car") {
return new Car();
}
if (type.toLowerCase() === "truck") {
return new Truck();
}
return null;
}
}
export default FourWheelTransportFactory;
TypeScriptFactory Producer Class [Producer]
// factory-producer.ts
import AbstractTransportFactory from "./abstract-transport-factory";
import FourWheelTransportFactory from "./four-wheel-transport-factory";
import TwoWheelTransportFactory from "./two-wheel-transport-factory";
class FactoryProducer {
static getFactory(numberOfWheels: number): (AbstractTransportFactory | null) {
if (numberOfWheels == 2) {
return new TwoWheelTransportFactory();
}
if (numberOfWheels == 4) {
return new FourWheelTransportFactory();
}
return null;
}
}
export default FactoryProducer;
TypeScriptDemo
// demo.ts
import FactoryProducer from "./factory-producer";
const transportFactory1 = FactoryProducer.getFactory(2);
const transport1 = transportFactory1?.getTransport("bicycle");
transport1?.start();
const transportFactory2 = FactoryProducer.getFactory(4);
const transport2 = transportFactory2?.getTransport("truck");
transport2?.start();
transport2?.stop();
TypeScriptOutput
Here is the output of the demo code.
Bicycle Started
Truck Started
Truck Stopped
PlaintextSource Code
Use the following link to get the source code:
Example | Source Code Link |
---|---|
Example #1: Transport | GitHub |
Other Code Implementations
Use the following links to check Abstract Factory pattern implementation in other programming languages.