Categories
JavaScript Design Patterns

JavaScript Design Patterns — Chain of Responsibility, Singleton, and Flyweight Patterns

Design patterns are the basis of any good software. JavaScript programs are no exception.

In this article, we’ll look at the chain of responsibility, singleton, and flyweight patterns.

Chain of Responsibility Pattern

The chain of responsibility is similar to the observer pattern, except that it sends the notification to one object, and then that object sends the notification to another object, and so on.

In the observer pattern, the notification is sent to all the observers at the same time.

For instance, if we send something to one object and then that object picks that up and does something with and send that to another and so on, then that implements the chain of responsibility patterns.

We can implement that as follows:

const backend = {
  receive(data) {
    // do something with data
  }
}

const middleLayer = {
  notify(data) {
    backend.receive(data);
  }
}

const frontEnd = {
  notify(data) {
    middleLayer.notify(data);
  }
}

In the code above, we have the frontEnd , which calls the notify method of the middleLayer object, which in turn called the backend ‘s receive method.

This way, we can pass data between them with one method seamlessly.

As long as we don’t expose any other methods that do communication between both objects, we have a clean way of sending data between frontEnd and middleLayer and backEnd .

Singleton

The singleton pattern is where we only instantiate one instance of an object.

In JavaScript, we can create objects with one instance by creating an object literal.

We can create one by writing:

const obj = {
  foo: 1,
  bar: 'baz'
}

An object literal is just sets of key-value pairs, where the value can also be other objects.

If we use classes, we can also write:

class Foo {
  constructor() {
    if (!Foo.instance) {
      Foo.instance = {
        foo: 1,
        bar: 2
      }
    }
    return Foo.instance;
  }
}

We assigned the created instance to the instance property of Foo .

Then when we create the constructor, we check the instance property to see if anything’s created for it.

If there’s nothing assigned to it then we assign an object to it.

Then we return Foo.instance so that we get the instance.

Now if we create 2 instances of Foo :

const foo = new Foo();
const bar = new Foo();

Then we can see if they’re the same instance by writing:

console.log(foo === bar);

We should get true since they both reference the same instance.

Singletons are handy for creating objects that are used by multiple pieces of code to store data in a central place.

If we don’t want conflicts in how data is accessed, then we can create a singleton instance of a class or an object literal to make sure that there are no issues with conflicts.

Flyweight Pattern

The flyweight pattern is where we restrict object creation,

We create a set of small objects that each consume a smaller amount of resources.

These objects sit behind a flyweight object, which is used to interact with these objects,

Those objects also interact with our code.

This way, we get the benefits of a big object, while we interact with smaller objects that are more manageable.

For instance, we can implement it as follows:

class Student {
 //..
}

const studentIdentity = {
 getIdentity(){
   const student = new Student();
    //..
    return {
    //...
    }
  }
}

const studentScore = {
 getScore(){
   const student = new Student();
    //..
    return {
    //...
    }
  }
}

We have a Student class that represents a student’s data.

Then in the studentIdentity and studentScore objects, we have methods to get his or her identity or score respectively.

This way, we don’t have to put all the methods into the Student class.

Instead, we have methods outside of it that are smaller that we can use to deal with specific kinds of student data.

Conclusion

We can use the singleton pattern to create one-off objects.

We can either create class instances with only one instance or with object literals.

The flyweight pattern is where we create smaller objects to deal with big objects, thereby reducing complexity.

The chain of responsibility pattern lets us send data from one object to another in a series fashion.

Categories
JavaScript Design Patterns

JavaScript Design Patterns — Factory Pattern

Design patterns are the basis of any good software. JavaScript programs are no exception.

In this article, we’ll look at the factory and observer patterns.

Factory Pattern

The factory pattern is a design pattern that lets us create new objects and return them in a clean way.

For instance, we may want to return different kinds of things that are similar.

To make this easy for us, we can create a factory function that lets us return different kinds of objects with one factory function.

We can write:

class Fruit {
  //...
}

class Apple extends Fruit {
  //...
}

class Orange extends Fruit {
  //...
}

const fruitFactory = (type) => {
  if (type === 'apple') {
    return new Apple()
  } else if (type === 'orange') {
    return new Apple()
  }
}

We have the fruitFactory factory function that gets the type of an object as the argument and then return an object according to the type.

If we have 'apple' as the value of type , we return an Apple instance.

And if we type set to 'orange' , we return an Orange instance.

Now we can return different subclass instances of Fruit without writing them out explicitly.

If we make any changes to the class or add or remove them, then we can still use the same factory function and don’t break anything.

Some factory functions in JavaScript are in the standard library.

They include String for creating strings, Number for creating numbers from other entities, Boolean for convert variables to boolean, Array for creating arrays, and more.

Now we don’t have to worry about changes to the class structure messing up our code since we used a factory function to create our Fruit objects.

Observer

The observer pattern is where we have multiple objects that listen to the one observable object.

This way, the observable object, which is also called the subject, can notify the objects that subscribed to the observable object with data that are emitted.

For instance, we can write:

const observable = {
  observers: {},
  subscribe(obj) {
    const id = Object.keys(this.observers).length + 1;
    this.observers[id] = obj;
    return id;
  },

  notify(data) {
    for (const o of Object.keys(this.observers)) {
      this.observers[o].listen(data);
    }
  }
}

const observer = {
  listen(data) {
    console.log(data);
  }
}
observable.subscribe(observer);
observable.notify({
  a: 1
});

We have the observable object that lets observer objects, which have a listen method to listen to data, to subscribe to notifications from the observable object.

When we can observable.notify with something as we did above, the listen method of the observer objects is run.

This way, the communication is all done by communicating via the notify method and nowhere else.

No implementations are exposed and therefore no tight coupling.

As long as the methods do the same thing, we shouldn’t have to worry about breaking the observer objects that subscribe to the observable .

We can also add an unsubscribe method to observable which uses the returned id from subscribe to remove an observer object from the observers object.

For instance, we can write:

const observable = {
  observers: {},
  subscribe(obj) {
    const id = Object.keys(this.observers).length + 1;
    this.observers[id] = obj;
    return id;
  },

  notify(data) {
    for (const o of Object.keys(this.observers)) {
      this.observers[o].listen(data);
    }
  },

  unsubscribe(id) {
    delete this.observers[id];
  }
}

const observer = {
  listen(data) {
    console.log(data);
  }
}
const subscriberId = observable.subscribe(observer);
observable.notify({
  a: 1
});

observable.unsubscribe(subscriberId);

We added an unsubscribe method so that we can remove the observer object from the this.observers list.

Once we unsubscribed, we won’t get notifications any more with the unsubscribed observer if we call notify again.

Examples of the observer pattern are used in many places.

Another good thing about the observer pattern is that we don’t communicate anything through the classes.

Loose coupling should always be preferred to tight coupling.

We only communicate through one channel in the example above so the observer pattern is as loose as coupling can get.

They include message queues and event handlers for GUI events like mouse clicks and key presses.

Conclusion

We can use the observer pattern to decouple objects as much as possible.

All we do is receive events from one observable object that we want changes from.

The observable sends notifications to observer objects.

The factory pattern lets us create objects of similar types in one place by creating a factory function that lets us do that.

Categories
JavaScript Design Patterns

JavaScript Design Patterns — Strategy and Decorator Pattern

Design patterns are the basis of any good software. JavaScript programs are no exception.

In this article, we’ll look at the strategy and decorator design patterns.

Strategy Pattern

The strategy design pattern is a design pattern that lets us select from a family of algorithms during run time.

The algorithms should be substitutable with each other.

This pattern’s main idea is to let us create multiple algorithms for solving the same problem.

We have one object that does things one way and another that does things another way.

There may be more than one way to do the same thing.

For instance, we may have one function that calls a function depending on what we want to do.

We may write:

const smartStrategy = () => {
  //..
}

const smarterStrategy = () => {
  //..
}

const dumbStrategy = () => {
  //..
}

const doTask = () => {
  if (shouldBeSmart) {
    smartStrategy()
  } else if (shouldBeSmarter) {
    smarterStrategy()
  } else if (shouldBeDumb) {
    dumbStrategy()
  }
}

We have the doTask function that runs the functions that have the strategies that we want to use to accomplish a task.

This way, we can pick the algorithm that suits the task the most.

This can be from a user setting or it can be chosen automatically.

The whole idea is to define a family of algorithms, encapsulate each one, and make them interchangeable.

Making them interchangeable is important since we want them to accomplish the same results at the end.

The strategy pattern is good for separating volatile code from a part of the program so that the part that changes are separate from the stable code.

Also, using the strategy pattern, we don’t have to split the implementation code over several inherited classes as often.

Using this pattern reduces the chance of having many child classes for one parent class.

This is a simple pattern that let us choose different ways to do the same thing and reduce the risk of volatile code that break things by separating them out.

Algorithms are encapsulated by one interface that doesn’t change so that outside code can just use that instead of changing the inner workings of the code all the time.

Closed for Modification, Open for Extension

In the same vein, once we wrote some code, we shouldn’t be modifying them too often.

Instead, they should be open to extensions so that we can add capabilities to them later.

Changing code always introduces risks. The more changes we make, the higher the chance that we break things.

Therefore, we should just extend things as much as possible so that the existing code stays untouched.

Decorator Pattern

The decorator pattern is a pattern where we write wrapper code to let us extend the core code.

We just keep wrapping objects around objects that we want to use so that we keep extending the capabilities of the existing objects by defining new objects that have the capabilities of the existing object.

For instance, we can write:

const computer = {
  //...
  description() {
    //...
  }
};

const disk = {
  ///...
  computer,
  description() {
    //...
  }
}

const laptop = {
  ///...
  disk
}

The computer object has the core capabilities of a computer.

Then we extend the capabilities of disk with by putting the computer object inside the disk object.

Then we create a laptop object, that has the disk object, which has the computer object.

Now we created extensions computer , which are disk and laptop , without modifying the computer object itself.

That’s a safe way to add capabilities to computer without the risks of modifying computer directly.

Modifying things directly may break the thing itself or the things that use it.

Likewise, we can use the same pattern as an object but replacing them with classes.

For instance, we can write:

class Computer {
  //...
  description() {
    //...
  }
}

class Disk {
  constructor() {
    this.computer = new Computer();
  }
  //...

  description() {
    //...
  }
}

const laptop = {
  constructor() {
    this.disk = new Disk();
  }
  //...
}

We nest the Disk and Computer instances within Laptop so we can use them.

Conclusion

The strategy pattern lets us use different ways of solving the same problem by encapsulating them within one entity that can be invoked directly.

With this pattern, the strategies themselves are hidden from the outside.

With the decorator pattern, we can extend the capabilities of things by creating new things rather than changing things directly.

This reduces the chance of breaking things.

Categories
JavaScript Design Patterns

JavaScript Design Patterns — Composition, Inheritance, and Configuration

Design patterns are the basis of any good software. JavaScript programs are no exception.

In this article, we’ll look at the difference between composition and inheritance, and look at why we should make our program have some flexibility.

Composition Versus Inheritance

Composition is when our object contains other objects.

Inheritance is when we receive the parent object’s members in the current object.

They both have their place.

Composition is a has-a relationship while inheritance is a has-a relationship.

It’s very important to make distinctions between the 2 since they do different things.

In JavaScript, there’re various ways that 2 things are composed.

For instance, we can have functions that are nested in other functions.

We can write:

const foo = fn => {
  //...
  fn();
  //...
}

We have a foo function that calls fn .

Also, we can have nested objects. For example, we can write:

const obj = {
  foo: 1,
  bar: {
    baz: 2,
  }
}

We have an object as the value of bar .

We can also have functions as values of object properties.

Composition is used for holding functionality that’s needed by something.

Inheritance, on the other hand, is an is-a relationship.

This means a child object is also a parent object. It’s just that a child object may have additional things.

For instance, if we have:

class Animal {
  //...
}

class Cat extends Animal {
  //...
}

Then Cat is a subclass of Animal . Cat is an animal.

Cat shares all the members of Animal .

We can any methods ofAnimal and access any instance variables of Animal from a Cat instance.

For example, we can write:

class Animal {
  speak() {
    //...
  }
}
class Cat extends Animal {
  //...
}

The extends keyword indicates that Cat inherits the members of Animal .

Then if we create a Cat instance, we can write:

const cat = new Cat();

Then we can call speak by calling:

cat.speak();

Likewise, we can create an is-a relationship between 2 objects with the Object.create method:

const animal = {
  speak() {
    //...
  }
}

const cat = Object.create(animal);

Object.create takes a prototype object which will be the prototype of the child object.

So animal is the parent of cat in the example above.

Like with class instances, we can call speak by writing cat.speak() .

In both the class and object examples, the prototype of the object resides in the __proto__ property of the object.

Inheritance is good for creating multiple classes or objects that share things from the parent class or object respectively.

The general principle is that if we have volatile code, then we should use more has-a relationships rather than an is-a relationship since we assume that shared code between a parent and different children may change.

If we change shared code between parents and children, then we break all the children as well.

Creating Algorithms

Once we decided on the patterns to use, then we’ve to devise our algorithm for our program.

This should be easy once we created some basic designs. Implementation is all that’s needed in most cases.

We can use existing libraries to make our lives easier, which is what we should do in most cases.

If we have an is-a relationship between classes or objects, then we need to think about which pieces of code are shared and which ones are unique to classes or objects.

If we use a has-a model instead, then we can create algorithms in different places and use them as we wish to.

We should think about making our program configurable so that we don’t have to change code to have slightly different functionality.

This way, we make our lives easier since code change always has some risks.

To reduce that, we should make things that change frequently be configurable so that we don’t have to deal with them.

For instance, we can read settings from a file or database so an algorithm can be selected according to settings that are set in those places.

Conclusion

Our programs should have some flexibility so that we don’t have to change code for it to do different things.

Composition is when we have something in an object or class so we can use them as we wish.

Inheritance is when we have some shared code that’s used by other objects or classes.

Categories
JavaScript Design Patterns

JavaScript Design Patterns — Adapters and Facades

Design patterns are the basis of any good software. JavaScript programs are no exception.

In this article, we’ll look at the adapter and facade patterns.

Adapter

The adapter pattern is useful for creating a consistent interface for another object.

The object we’re creating an interface for doesn’t fit with how it’s used.

Therefore, we create an adapter so that we can use them easily.

It also hides the implementation so that we can use it easily and with low coupling.

For instance, we can create an adapter object as follows:

const backEnd = {
  setAttribute(key, value) {
    //.,,
  },
  getAttribute() {
    //...
  }
}

const personAdapter = {
  setFirstName(name) {
    backEnd.setAttribute('firstName', name);
  },
  setLastName(name) {
    backEnd.setAttribute('lastName', name);
  },
  getFirstName() {
    backEnd.getAttribute('firstName');
  },
  getLastName() {
    backEnd.getAttribute('lastName');
  }
}

We created an adapter object called personAdapter so that we can use backEnd to set all the attributes.

The adapter has an interface that people can understand more easily since the method names are explicit.

Other objects or classes can use the object to manipulate the attributes.

We can use adapters to create interfaces that we want to expose to the public any way we want.

Inheriting Objects with Adapters

With adapters, we can also create an interface for multiple classes or objects.

For instance, we can write:

const backEnd = {
  setAttribute(key, value) {
    //.,,
  },
  getAttribute() {
    //...
  }
}

const parentAdapter = {
  //...
  getAdapterName() {
    //...
  }
}

const personAdapter = Object.create(parentAdapter);

personAdapter.setFirstName = (name) => {
  backEnd.setAttribute('firstName', name);
};

personAdapter.setLastName = (name) => {
  backEnd.setAttribute('lastName', name);
};

personAdapter.getFirstName = () => {
  backEnd.getAttribute('firstName');
};

personAdapter.getLastName = () => {
  backEnd.getAttribute('lastName');
}

In the code above, we created personAdapter with Object.create , which allows us to inherit from another parent object.

So we get the getAdapterName method from the parentAdapter prototype object.

Then we add our own methods to personAdapter .

Now we can get inherited methods from another object plus the methods in our own adapter object in the adapter.

Likewise, we can do the same with the class syntax.

For instance, we can create an adapter class instead of an object.

We can write:

const backEnd = {
  setAttribute(key, value) {
    //.,,
  },
  getAttribute() {
    //...
  }
}

class ParentAdapter {
  //...
  getAdapterName() {
    //...
  }
}

class PersonAdapter extends ParentAdapter {
  setFirstName(name) {
    backEnd.setAttribute('firstName', name);
  }

  setLastName(name) {
    backEnd.setAttribute('lastName', name);
  }

  getFirstName() {
    backEnd.getAttribute('firstName');
  }

  getLastName() {
    backEnd.getAttribute('lastName');
  }

}

const personAdapter = new PersonAdapter();
console.log(personAdapter);

The code above has a PersonAdapter and ParentAdapter classes instead of objects.

We used the extends keyword to inherit members from ParentAdapter .

This is another way we can inherit members from a parent entity.

Facade Pattern

We can use the facade pattern to create a class or object to hide the implementation of something complex behind it.

This is used to create an easy to use interface for the outside while keeping the complex implementation of something inside.

For instance, we can write:

const complexProduct = {
  setShortName(name) {
    //...
  },

  setLongName(name) {
    //...
  },

  setPrice(price) {
    //...
  },

  setDiscount(discount) {
    //...
  },
  //...
}

const productFacade = {
  setName(type, name) {
    if (type === 'shortName') {
      complexProduct.setShortName(name);
    } else if (type === 'longName') {
      complexProduct.setLongName(name);
    }
  }
  //...
}

We created a productFacade that has some methods that call various methods in the complexProduct object.

This way, we can use the facade to simplify what we do, and also reduce the coupling to the complexProduct object.

We let the productFacade object communicates with the complexProduct object.

It also serves to reduce coupling from complex objects.

In addition, a facade can also create an interface for something that won’t change as often as what’s behind it.

An interface that doesn’t change as often is good since more changes mean more risks of bugs.

Likewise, we can create a facade class that does the same thing as follows:

const complexProduct = {
  setShortName(name) {
    //...
  },

  setLongName(name) {
    //...
  },

  setPrice(price) {
    //...
  },

  setDiscount(discount) {
    //...
  },
  //...
}

class ProductFacade {
  setName(type, name) {
    if (type === 'shortName') {
      complexProduct.setShortName(name);
    } else if (type === 'longName') {
      complexProduct.setLongName(name);
    }
  }
  //...
}

Then we can create an instance of ProductFacade instead of using the object literal directly.

A facade can be used to manipulate one or more objects. That’s different from the adapter pattern, where we make an adapter for one object.

Conclusion

We can use the adapter pattern to hide the implementation of one object bu creating an interface that’s easier to work with to the outside.

The facade pattern lets us hide complex implementations behind one interface that can be used instead of one or more complex objects being the facade.