Abstract Factory Design Pattern
Video Lecture
Overview
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Terminology
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Abstract Factory UML Diagram

Source Code
./src/abstract-factory/abstract-factory-concept.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | // Abstract Factory Concept Sample Code
import { FactoryA, IProductA } from './factory-a'
import { FactoryB, IProductB } from './factory-b'
interface IProduct extends IProductA, IProductB {}
class AbstractFactory {
// The Abstract Factory Concrete Class
static createObject(factory: string): IProduct | undefined {
try {
if (['aa', 'ab', 'ac'].indexOf(factory) > -1) {
return FactoryA.getObject(factory[1])
}
if (['ba', 'bb', 'bc'].indexOf(factory) > -1) {
return FactoryB.getObject(factory[1])
}
throw new Error('No Factory Found')
} catch (e) {
console.log(e)
}
}
}
// The Client
let PRODUCT = AbstractFactory.createObject('ab')
console.log(PRODUCT)
PRODUCT = AbstractFactory.createObject('bc')
console.log(PRODUCT)
|
./src/abstract-factory/factory-a.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 | // FactoryA Sample Code
export interface IProductA {
name: string
}
class ConcreteProduct implements IProductA {
name = ''
}
class ConcreteProductA extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryA:ConcreteProductA'
}
}
class ConcreteProductB extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryA:ConcreteProductB'
}
}
class ConcreteProductC extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryA:ConcreteProductC'
}
}
export class FactoryA {
static getObject(some_property: string): IProductA {
try {
if (some_property === 'a') {
return new ConcreteProductA()
} else if (some_property === 'b') {
return new ConcreteProductB()
} else if (some_property === 'c') {
return new ConcreteProductC()
} else {
throw new Error('Class Not Found')
}
} catch (e) {
console.log(e)
}
return new ConcreteProduct()
}
}
|
./src/abstract-factory/factory-b.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 | // FactoryB Sample Code
export interface IProductB {
name: string
}
class ConcreteProduct implements IProductB {
name = ''
}
class ConcreteProductA extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryB:ConcreteProductA'
}
}
class ConcreteProductB extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryB:ConcreteProductB'
}
}
class ConcreteProductC extends ConcreteProduct {
constructor() {
super()
this.name = 'FactoryB:ConcreteProductC'
}
}
export class FactoryB {
static getObject(some_property: string): IProductB {
try {
if (some_property === 'a') {
return new ConcreteProductA()
} else if (some_property === 'b') {
return new ConcreteProductB()
} else if (some_property === 'c') {
return new ConcreteProductC()
} else {
throw new Error('Class Not Found')
}
} catch (e) {
console.log(e)
}
return new ConcreteProduct()
}
}
|
Output
node ./dist/abstract-factory/abstract-factory-concept.js
ConcreteProductB { name: 'FactoryA:ConcreteProductB' }
ConcreteProductC { name: 'FactoryB:ConcreteProductC' }
Abstract Factory Example Use Case
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Abstract Factory Example UML Diagram
See this UML diagram of an Abstract Furniture Factory implementation that returns chairs
and tables.

Source Code
./src/abstract-factory/client.ts
| // Abstract Factory Use Case Example Code
import FurnitureFactory from './furniture-factory'
let FURNITURE = FurnitureFactory.getFurniture('SmallChair')
console.log(FURNITURE?.name)
console.log(FURNITURE?.getDimensions())
FURNITURE = FurnitureFactory.getFurniture('MediumTable')
console.log(FURNITURE?.name)
console.log(FURNITURE?.getDimensions())
|
./src/abstract-factory/dimension.ts
| export type dimension = {
height: number
width: number
depth: number
}
|
./src/abstract-factory/furniture-factory.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | // Abstract Furniture Factory
import { IChair } from './chair'
import ChairFactory from './chair-factory'
import { ITable } from './table'
import TableFactory from './table-factory'
interface IFurniture extends IChair, ITable {}
export default class FurnitureFactory {
static getFurniture(furniture: string): IFurniture | undefined {
try {
if (
['SmallChair', 'MediumChair', 'BigChair'].indexOf(
furniture
) > -1
) {
return ChairFactory.getChair(furniture)
}
if (
['SmallTable', 'MediumTable', 'BigTable'].indexOf(
furniture
) > -1
) {
return TableFactory.getTable(furniture)
}
throw new Error('No Factory Found')
} catch (e) {
console.log(e)
}
}
}
|
./src/abstract-factory/chair-factory.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | import SmallChair from './small-chair'
import MediumChair from './medium-chair'
import BigChair from './big-chair'
import { IChair } from './chair'
export default class ChairFactory {
static getChair(chair: string): IChair {
if (chair == 'BigChair') {
return new BigChair()
} else if (chair == 'MediumChair') {
return new MediumChair()
} else if (chair == 'SmallChair') {
return new SmallChair()
} else {
throw new Error('No Chair Found')
}
}
}
|
./src/abstract-factory/chair.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | import { dimension } from './dimension'
export interface IChair {
name: string
height: number
width: number
depth: number
getDimensions(): dimension
}
export class Chair implements IChair {
name = ''
height = 0
width = 0
depth = 0
getDimensions(): dimension {
return {
width: this.width,
depth: this.depth,
height: this.height,
}
}
}
|
./src/abstract-factory/small-chair.ts
| import { Chair } from './chair'
export default class SmallChair extends Chair {
constructor() {
super()
this.name = 'SmallChair'
this.height = 40
this.width = 40
this.depth = 40
}
}
|
./src/abstract-factory/medium-chair.ts
| import { Chair } from './chair'
export default class MediumChair extends Chair {
constructor() {
super()
this.name = 'MediumChair'
this.height = 60
this.width = 60
this.depth = 60
}
}
|
./src/abstract-factory/big-chair.ts
| import { Chair } from './chair'
export default class BigChair extends Chair {
constructor() {
super()
this.name = 'BigChair'
this.height = 80
this.width = 80
this.depth = 80
}
}
|
./src/abstract-factory/table-factory.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | import SmallTable from './small-table'
import MediumTable from './medium-table'
import BigTable from './big-table'
import { ITable } from './table'
export default class TableFactory {
static getTable(table: string): ITable {
if (table === 'BigTable') {
return new BigTable()
} else if (table === 'MediumTable') {
return new MediumTable()
} else if (table === 'SmallTable') {
return new SmallTable()
} else {
throw new Error('No Table Found')
}
}
}
|
./src/abstract-factory/table.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | import { dimension } from './dimension'
export interface ITable {
name: string
height: number
width: number
depth: number
getDimensions(): dimension
}
export class Table implements ITable {
name = ''
height = 0
width = 0
depth = 0
getDimensions(): dimension {
return {
width: this.width,
depth: this.depth,
height: this.height,
}
}
}
|
./src/abstract-factory/small-table.ts
| import { Table } from './table'
export default class SmallTable extends Table {
constructor() {
super()
this.name = 'SmallTable'
this.height = 40
this.width = 40
this.depth = 40
}
}
|
./src/abstract-factory/medium-table.ts
| import { Table } from './table'
export default class MediumTable extends Table {
constructor() {
super()
this.name = 'MediumTable'
this.height = 60
this.width = 60
this.depth = 60
}
}
|
./src/abstract-factory/big-table.ts
| import { Table } from './table'
export default class BigTable extends Table {
constructor() {
super()
this.name = 'BigTable'
this.height = 80
this.width = 80
this.depth = 80
}
}
|
Output
node ./dist/abstract-factory/client.js
SmallChair
{ width: 40, depth: 40, height: 40 }
MediumTable
{ width: 60, depth: 60, height: 60 }
Summary
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.