Javascript Design Patterns

Singleton Pattern | Factory Pattern | Constructor Pattern

Topics

  • Singleton Pattern
  • Factory Pattern
  • Factory Pattern vs Constructor Pattern

Singleton Pattern (uses Redux or React Context)

  • Singleton design pattern exposes a single instance that can be used by multiple components
  • Singleton Pattern can be considered the basics of global state management libraries such Redux or React Context.
  • It is a pattern that restricts the class to create only one instance.
  • They can be accessed globally and acts as a single access point for accessing the global state.
let instance;
let globalState = {
color: ""
};

class StateUtility {
constructor() {
if (instance) {
throw new Error("New instance cannot be created!!");
}
instance = this;
}
getPropertyByName(propertyName) {
return globalState[propertyName];
}
setPropertyValue(propertyName, propertyValue) {
globalState[propertyName] = propertyValue;
}
}
let stateUtilityInstance = Object.freeze(new StateUtility());
export default stateUtilityInstance;
  • We make sure that we don’t expose the globalState. We expose them using the class methods of StateUtility. In this way, we protect the global state from being altered directly.
  • Finally, we create the instance of the class as follows: let stateUtilityInstance = Object.freeze(new StateUtility());.
  • We have used Object.freeze so that no other class/component/module is able to modify the exposed stateUtilityInstance.

Factory Pattern (Factory pattern vs Constructors) —

  • A factory is an object or class or a function in a functional programming paradigm for creating objects.
  • Factory Method creates new objects as instructed by the client. One way to create objects in JavaScript is by invoking a constructor function with the new operator
  • Factory design pattern is used when we have a superclass with multiple sub-classes and based on input, we need to return one of the sub-class. This pattern takes out the responsibility of the instantiation of a class from the client program to the factory class.
  • Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
  • Factory Methods are frequently used in applications that manage, maintain, or manipulate collections of objects that are different but at the same time have many characteristics (i.e. methods and properties) in common.
  • Factory pattern can use a constructor or class inside But the factory pattern is preferred in cases where the object creation process depends on dynamic factors — such as when we want to dynamically create subclasses.
  • Factory gives us an object creation mechanism that is both flexible and reusable.
// creates factory function
function vehicleFactory (manufacturer, plateNO) {
return {
manufacturer,
plateNO,
startEngine () {
console.log("reving engine")
},
drive () {
console.log("driving car...")
}
}
}

const Vehicle1 = vehicleFactory("Toyota", 12345);
console.log(Vehicle1)
// prints
//{
// manufacturer: 'Toyota',
// plateNO: 12345,
// startEngine: [Function: startEngine],
// drive: [Function: drive]
//}

const Vehicle2 = vehicleFactory("Ford", 13345);
console.log(Vehicle2)
// prints
// {
// manufacturer: 'Ford',
// plateNO: 13345,
// startEngine: [Function: startEngine],
// drive: [Function: drive]
// }

Examples,

  • Factory pattern promotes code reusability by reusing the StartEngine, driveVehicle, and stopEngine methods.
class Car {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "silver";
}
}

class Truck {
constructor(options) {
this.wheels = options.wheels || 6;
this.doors = options.doors || 2;
this.color = options.color || "red";
}
}


class Factory {

create = (options, vehicleType) => {

if(!vehicleType) {
return "unable to make vehicle. Please specify a vehicle type and tryagain!"
}

let vehicle;

if (vehicleType === "car") {
vehicle = new Car(options);
} else if (vehicleType === "truck") {
vehicle = new Truck(options);
}


vehicle.vehicleType = vehicleType;

vehicle.startEngine = ()=> console.log(`Reving ${vehicleType} engine`);

vehicle.driveVehicle = ()=> console.log(`Driving ${vehicleType}...`);

vehicle.stopEngine = ()=> console.log(`Stop ${vehicleType} engine`);

return vehicle;
}

};

const vehicleFactory = new Factory();

const car = vehicleFactory.create({
wheels: 4,
doors: 2,
color: "black",
}, "car");

console.log(car)
console.log(car.startEngine())
console.log(car.driveVehicle())

// prints:
//Car {
// wheels: 4,
// doors: 4,
// color: 'silver',
// vehicleType: 'car',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving car engine
// Driving car...

const truck = vehicleFactory.create({
wheels: 4,
doors: 2,
color: "yellow",
}, "truck")

console.log(truck)
console.log(truck.startEngine())
console.log(truck.stopEngine())
// prints
//Truck {
// wheels: 4,
// doors: 2,
// color: 'yellow',
// vehicleType: 'truck',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving truck engine
// Stop truck engine
  • By using the factory pattern our code is also easily maintainable, so if the business expands and the factory starts producing new kinds of vehicles, we can easily refractory our implementation to handle this as seen below:
class Car {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "silver";
}
}

class Truck {
constructor(options) {
this.wheels = options.wheels || 6;
this.doors = options.doors || 2;
this.color = options.color || "red";
}
}

class Bus {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "white";
}
}

class Motorcycle {
constructor(options) {
this.wheels = options.wheels || 2;
this.doors = options.doors || 0;
this.color = options.color || "Black";
}
}


class Factory {

create = (options, vehicleType) => {

if(!vehicleType) {
return "unable to make vehicle. Please specify a vehicle type and tryagain!"
}

let vehicle;

if (vehicleType === "car") {
vehicle = new Car(options);
} else if (vehicleType === "truck") {
vehicle = new Truck(options);
} else if (vehicleType === "bus") {
vehicle = new Bus(options);
} else if (vehicleType === "motorcycle") {
vehicle = new Motocycle(options);
}


vehicle.vehicleType = vehicleType;

vehicle.startEngine = ()=> console.log(`Reving ${vehicleType} engine`);

vehicle.driveVehicle = ()=> console.log(`Driving ${vehicleType}...`);

vehicle.stopEngine = ()=> console.log(`Stop ${vehicleType} engine`);

return vehicle;
}

};

const vehicleFactory = new Factory();

const bus = vehicleFactory.create({
wheels: 4,
doors: 4,
color: "yellow",
}, "bus");

console.log(bus)
console.log(bus.startEngine())
console.log(bus.driveVehicle())

// prints:
// Bus {
// wheels: 4,
// doors: 4,
// color: 'yellow',
// vehicleType: 'bus',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving bus engine
// Driving bus...

const bike = vehicleFactory.create({
wheels: 2,
doors: 0,
color: "red",
}, "motorcycle")

console.log(bike)
console.log(bike.startEngine())
console.log(bike.stopEngine())
// prints
// Motorcycle {
// wheels: 2,
// doors: 0,
// color: 'red',
// vehicleType: 'bike',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving motorcycle engine
// Stop motorcycle engine

More examples,

var Factory = function () {
this.createEmployee = function (type) {
var employee;

if (type === "fulltime") {
employee = new FullTime();
} else if (type === "parttime") {
employee = new PartTime();
} else if (type === "temporary") {
employee = new Temporary();
} else if (type === "contractor") {
employee = new Contractor();
}

employee.type = type;

employee.say = function () {
console.log(this.type + ": rate " + this.hourly + "/hour");
}

return employee;
}
}

var FullTime = function () {
this.hourly = "$12";
};

var PartTime = function () {
this.hourly = "$11";
};

var Temporary = function () {
this.hourly = "$10";
};

var Contractor = function () {
this.hourly = "$15";
};

function run() {

var employees = [];
var factory = new Factory();

employees.push(factory.createEmployee("fulltime"));
employees.push(factory.createEmployee("parttime"));
employees.push(factory.createEmployee("temporary"));
employees.push(factory.createEmployee("contractor"));

for (var i = 0, len = employees.length; i < len; i++) {
employees[i].say();
}
}

Factory pattern vs Constructors

  • The constructor pattern and factory pattern are similar because they are object creation patterns that return a new object
  • Factory method can return an already created object, unlike a constructor, which always creates a new instance.
  • Factory methods promote the idea of coding using Interface then implementation which results in more flexible code, but constructor ties your code to a particular implementation.
  • Reasons to use constructors: We use constructors to initialize the object with the default or initial state. The default values for primitives may not be what are you looking for. Another reason to use constructor is that it informs about dependencies.
  • Reason to use Factory: Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code.
const vehicleOptions = {type: "cars", color: "white", doors: 4, wheels: 4}

// factory pattern
function Factory(options) {
let factory = {};
factory.type = options.type;
factory.color = options.color;
factory.wheels = options.wheels;
factory.doors = options.doors;

return factory;
}

const vehicle = Factory(vehicleOptions);

// constructor pattern
function ConstructorPattern(options) {
this.type = options.type;
this.color = options.color
this.doors = options.doors;
this.wheels = options.wheels;
}

const vehicle2 = new ConstructorPattern(vehicleOptions);

console.log("factory car", vehicle)
// prints { type: 'cars', color: 'white', wheels: 4, doors: 4 }

console.log("constructor car", vehicle2)
// prints { type: 'cars', color: 'white', wheels: 4, doors: 4 }

When to Use the Factory Pattern

The Factory pattern can be especially useful when applied to the following situations:

  • When our object or component setup involves a high level of complexity.
  • When we need to easily generate different instances of objects depending on the environment we are in.
  • When we’re working with many small objects or components that share the same properties.
  • When composing objects with instances of other objects that need only satisfy an API contract (a.k.a., duck typing) to work. This is useful for decoupling.

Thanks for reading

I know there would always be something to improve. Please feel free to share your thoughts


Javascript Design Patterns was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Javascript Hungry | Working at Walmart

Singleton Pattern | Factory Pattern | Constructor Pattern

Topics

  • Singleton Pattern
  • Factory Pattern
  • Factory Pattern vs Constructor Pattern

Singleton Pattern (uses Redux or React Context)

  • Singleton design pattern exposes a single instance that can be used by multiple components
  • Singleton Pattern can be considered the basics of global state management libraries such Redux or React Context.
  • It is a pattern that restricts the class to create only one instance.
  • They can be accessed globally and acts as a single access point for accessing the global state.
let instance;
let globalState = {
color: ""
};

class StateUtility {
constructor() {
if (instance) {
throw new Error("New instance cannot be created!!");
}
instance = this;
}
getPropertyByName(propertyName) {
return globalState[propertyName];
}
setPropertyValue(propertyName, propertyValue) {
globalState[propertyName] = propertyValue;
}
}
let stateUtilityInstance = Object.freeze(new StateUtility());
export default stateUtilityInstance;
  • We make sure that we don’t expose the globalState. We expose them using the class methods of StateUtility. In this way, we protect the global state from being altered directly.
  • Finally, we create the instance of the class as follows: let stateUtilityInstance = Object.freeze(new StateUtility());.
  • We have used Object.freeze so that no other class/component/module is able to modify the exposed stateUtilityInstance.

Factory Pattern (Factory pattern vs Constructors) —

  • A factory is an object or class or a function in a functional programming paradigm for creating objects.
  • Factory Method creates new objects as instructed by the client. One way to create objects in JavaScript is by invoking a constructor function with the new operator
  • Factory design pattern is used when we have a superclass with multiple sub-classes and based on input, we need to return one of the sub-class. This pattern takes out the responsibility of the instantiation of a class from the client program to the factory class.
  • Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
  • Factory Methods are frequently used in applications that manage, maintain, or manipulate collections of objects that are different but at the same time have many characteristics (i.e. methods and properties) in common.
  • Factory pattern can use a constructor or class inside But the factory pattern is preferred in cases where the object creation process depends on dynamic factors — such as when we want to dynamically create subclasses.
  • Factory gives us an object creation mechanism that is both flexible and reusable.
// creates factory function
function vehicleFactory (manufacturer, plateNO) {
return {
manufacturer,
plateNO,
startEngine () {
console.log("reving engine")
},
drive () {
console.log("driving car...")
}
}
}

const Vehicle1 = vehicleFactory("Toyota", 12345);
console.log(Vehicle1)
// prints
//{
// manufacturer: 'Toyota',
// plateNO: 12345,
// startEngine: [Function: startEngine],
// drive: [Function: drive]
//}

const Vehicle2 = vehicleFactory("Ford", 13345);
console.log(Vehicle2)
// prints
// {
// manufacturer: 'Ford',
// plateNO: 13345,
// startEngine: [Function: startEngine],
// drive: [Function: drive]
// }

Examples,

  • Factory pattern promotes code reusability by reusing the StartEngine, driveVehicle, and stopEngine methods.
class Car {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "silver";
}
}

class Truck {
constructor(options) {
this.wheels = options.wheels || 6;
this.doors = options.doors || 2;
this.color = options.color || "red";
}
}


class Factory {

create = (options, vehicleType) => {

if(!vehicleType) {
return "unable to make vehicle. Please specify a vehicle type and tryagain!"
}

let vehicle;

if (vehicleType === "car") {
vehicle = new Car(options);
} else if (vehicleType === "truck") {
vehicle = new Truck(options);
}


vehicle.vehicleType = vehicleType;

vehicle.startEngine = ()=> console.log(`Reving ${vehicleType} engine`);

vehicle.driveVehicle = ()=> console.log(`Driving ${vehicleType}...`);

vehicle.stopEngine = ()=> console.log(`Stop ${vehicleType} engine`);

return vehicle;
}

};

const vehicleFactory = new Factory();

const car = vehicleFactory.create({
wheels: 4,
doors: 2,
color: "black",
}, "car");

console.log(car)
console.log(car.startEngine())
console.log(car.driveVehicle())

// prints:
//Car {
// wheels: 4,
// doors: 4,
// color: 'silver',
// vehicleType: 'car',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving car engine
// Driving car...

const truck = vehicleFactory.create({
wheels: 4,
doors: 2,
color: "yellow",
}, "truck")

console.log(truck)
console.log(truck.startEngine())
console.log(truck.stopEngine())
// prints
//Truck {
// wheels: 4,
// doors: 2,
// color: 'yellow',
// vehicleType: 'truck',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving truck engine
// Stop truck engine
  • By using the factory pattern our code is also easily maintainable, so if the business expands and the factory starts producing new kinds of vehicles, we can easily refractory our implementation to handle this as seen below:
class Car {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "silver";
}
}

class Truck {
constructor(options) {
this.wheels = options.wheels || 6;
this.doors = options.doors || 2;
this.color = options.color || "red";
}
}

class Bus {
constructor(options) {
this.wheels = options.wheels || 4;
this.doors = options.doors || 4;
this.color = options.color || "white";
}
}

class Motorcycle {
constructor(options) {
this.wheels = options.wheels || 2;
this.doors = options.doors || 0;
this.color = options.color || "Black";
}
}


class Factory {

create = (options, vehicleType) => {

if(!vehicleType) {
return "unable to make vehicle. Please specify a vehicle type and tryagain!"
}

let vehicle;

if (vehicleType === "car") {
vehicle = new Car(options);
} else if (vehicleType === "truck") {
vehicle = new Truck(options);
} else if (vehicleType === "bus") {
vehicle = new Bus(options);
} else if (vehicleType === "motorcycle") {
vehicle = new Motocycle(options);
}


vehicle.vehicleType = vehicleType;

vehicle.startEngine = ()=> console.log(`Reving ${vehicleType} engine`);

vehicle.driveVehicle = ()=> console.log(`Driving ${vehicleType}...`);

vehicle.stopEngine = ()=> console.log(`Stop ${vehicleType} engine`);

return vehicle;
}

};

const vehicleFactory = new Factory();

const bus = vehicleFactory.create({
wheels: 4,
doors: 4,
color: "yellow",
}, "bus");

console.log(bus)
console.log(bus.startEngine())
console.log(bus.driveVehicle())

// prints:
// Bus {
// wheels: 4,
// doors: 4,
// color: 'yellow',
// vehicleType: 'bus',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving bus engine
// Driving bus...

const bike = vehicleFactory.create({
wheels: 2,
doors: 0,
color: "red",
}, "motorcycle")

console.log(bike)
console.log(bike.startEngine())
console.log(bike.stopEngine())
// prints
// Motorcycle {
// wheels: 2,
// doors: 0,
// color: 'red',
// vehicleType: 'bike',
// startEngine: [Function],
// driveVehicle: [Function],
// stopEngine: [Function]
//}

// Reving motorcycle engine
// Stop motorcycle engine

More examples,

var Factory = function () {
this.createEmployee = function (type) {
var employee;

if (type === "fulltime") {
employee = new FullTime();
} else if (type === "parttime") {
employee = new PartTime();
} else if (type === "temporary") {
employee = new Temporary();
} else if (type === "contractor") {
employee = new Contractor();
}

employee.type = type;

employee.say = function () {
console.log(this.type + ": rate " + this.hourly + "/hour");
}

return employee;
}
}

var FullTime = function () {
this.hourly = "$12";
};

var PartTime = function () {
this.hourly = "$11";
};

var Temporary = function () {
this.hourly = "$10";
};

var Contractor = function () {
this.hourly = "$15";
};

function run() {

var employees = [];
var factory = new Factory();

employees.push(factory.createEmployee("fulltime"));
employees.push(factory.createEmployee("parttime"));
employees.push(factory.createEmployee("temporary"));
employees.push(factory.createEmployee("contractor"));

for (var i = 0, len = employees.length; i < len; i++) {
employees[i].say();
}
}

Factory pattern vs Constructors

  • The constructor pattern and factory pattern are similar because they are object creation patterns that return a new object
  • Factory method can return an already created object, unlike a constructor, which always creates a new instance.
  • Factory methods promote the idea of coding using Interface then implementation which results in more flexible code, but constructor ties your code to a particular implementation.
  • Reasons to use constructors: We use constructors to initialize the object with the default or initial state. The default values for primitives may not be what are you looking for. Another reason to use constructor is that it informs about dependencies.
  • Reason to use Factory: Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code.
const vehicleOptions = {type: "cars", color: "white", doors: 4, wheels: 4}

// factory pattern
function Factory(options) {
let factory = {};
factory.type = options.type;
factory.color = options.color;
factory.wheels = options.wheels;
factory.doors = options.doors;

return factory;
}

const vehicle = Factory(vehicleOptions);

// constructor pattern
function ConstructorPattern(options) {
this.type = options.type;
this.color = options.color
this.doors = options.doors;
this.wheels = options.wheels;
}

const vehicle2 = new ConstructorPattern(vehicleOptions);

console.log("factory car", vehicle)
// prints { type: 'cars', color: 'white', wheels: 4, doors: 4 }

console.log("constructor car", vehicle2)
// prints { type: 'cars', color: 'white', wheels: 4, doors: 4 }

When to Use the Factory Pattern

The Factory pattern can be especially useful when applied to the following situations:

  • When our object or component setup involves a high level of complexity.
  • When we need to easily generate different instances of objects depending on the environment we are in.
  • When we’re working with many small objects or components that share the same properties.
  • When composing objects with instances of other objects that need only satisfy an API contract (a.k.a., duck typing) to work. This is useful for decoupling.

Thanks for reading

I know there would always be something to improve. Please feel free to share your thoughts


Javascript Design Patterns was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Javascript Hungry | Working at Walmart


Print Share Comment Cite Upload Translate Updates
APA

Javascript Hungry | Working at Walmart | Sciencx (2022-11-17T21:48:57+00:00) Javascript Design Patterns. Retrieved from https://www.scien.cx/2022/11/17/javascript-design-patterns/

MLA
" » Javascript Design Patterns." Javascript Hungry | Working at Walmart | Sciencx - Thursday November 17, 2022, https://www.scien.cx/2022/11/17/javascript-design-patterns/
HARVARD
Javascript Hungry | Working at Walmart | Sciencx Thursday November 17, 2022 » Javascript Design Patterns., viewed ,<https://www.scien.cx/2022/11/17/javascript-design-patterns/>
VANCOUVER
Javascript Hungry | Working at Walmart | Sciencx - » Javascript Design Patterns. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/11/17/javascript-design-patterns/
CHICAGO
" » Javascript Design Patterns." Javascript Hungry | Working at Walmart | Sciencx - Accessed . https://www.scien.cx/2022/11/17/javascript-design-patterns/
IEEE
" » Javascript Design Patterns." Javascript Hungry | Working at Walmart | Sciencx [Online]. Available: https://www.scien.cx/2022/11/17/javascript-design-patterns/. [Accessed: ]
rf:citation
» Javascript Design Patterns | Javascript Hungry | Working at Walmart | Sciencx | https://www.scien.cx/2022/11/17/javascript-design-patterns/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.