Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
Design patterns are the basis of any good software. JavaScript programs are no exception.
In this article, we’ll look at how to building blocks of design patterns that good software are based on.
Design Patterns
We should follow some design patterns so that we can have a good organization of our code.
If our code if well-organized, then working with them won’t be a pain now or in the future.
The Big 4 Object-Oriented Programming Building Blocks
Almost all good design patterns are based on 4 building blocks. They should have the following for them to be good.
Abstraction
Abstraction is one of the building blocks of a good design pattern.
It’s the careful consideration of how we’re going to handle problems.
Abstractions aren’t a programming technique. It’s a way to conceptualize a problem before applying object-oriented techniques.
It’s a way for us to divide our program into natural segments.
If we don’t divide our program into small parts, we’ll have problems with managing the complexity.
We just got divide programs into small, reusable pieces so that we can deal with them.
In JavaScript, we can divide programs in different ways.
We can divide them into functions. So we can write:
const speak = () => {
//...
}
Then we can call it wherever it’s available.
We can also divide programs into classes. Classes serve as a mechanism to create new objects.
For instance, we can write:
class Animal {
//...
}
Then we can use the new
operator to invoke it as follows:
const animal = new Animal();
We can then access its members. Assuming that it has speak
method, we can write:
animal.speak();
Encapsulation
Encapsulation is wrapping methods and data into an object.
We want to do that so different objects won’t know too much about each other.
This way, we won’t have issues with items being accessed when they shouldn’t be.
We should hide as much as possible so that coupling between objects is as loose as possible.
If they’re loosely coupled, then when we change one object, the chance of it breaking the other is lower.
We can divide what we expose to the outside.
The parts that change the most can be hidden and we expose an interface to the outside that doesn’t change that much.
Polymorphism
Polymorphism allows us to write code with different object types and we can decide on which object we want it to be at runtime.
JavaScript doesn’t have a polymorphism in the sense that we can cast them items to whatever we want explicitly.
But since JavaScript objects are dynamic, we can add or remove properties on the fly.
So we can still morph our objects in a way that we want.
We can perform actions according to the type that we set the object to.
We can add and remove properties on the fly.
For instance, we can write:
animal.run = () => {
//...
}
to define a new method on an object.
We can also merge different objects with Object.assign
or the spread syntax.
For example, we can write:
const obj = Object.assign({}, foo, bar);
or:
const obj = {...foo, ...bar };
Both lines of code merge the foo
and bar
objects together.
Because of JavaScript’s dynamic nature, we don’t cast objects to different types directly for polymorphism.
Inheritance
Inheritance is where our objects inherit the properties and methods of another object.
There are a few ways to do this with JavaScript.
We can use the extends
keyword for classes or constructors:
class Animal {
//...
}
class Dog extends Animal {
//...
}
The extends
keyword indicates that we inherit the members of Animal
in the Dog
class.
When we create a Dog
instance, we’ll see the Animal
members in the __proto__
property of the Dog
instance.
If we create object literals, we can use the Object.create
method as follows:
const parent = {
foo: 1
};
const child = Object.create(parent);
Once we run the code above, child
would have foo
in the __proto__
property.
__proto__
is the immediate prototype of the current object.
A prototype is a template object which other objects can inherit members from.
We can access the properties of an object’s prototype by accessing them directly.
So we can write:
child.foo
to access the foo
property of child
.
Conclusion
Abstraction, encapsulation, polymorphism, and inheritance are the 4 building blocks of object-oriented design patterns.
They provide us with clear ways to divide our code. We should have these in mind when we design our programs.
Top comments (0)