In daily life, programmers may encounter many errors while writing code, and naturally they develop methods to solve these problems. The solutions developed by different printers in different projects are very similar to each other. This is where Design Patterns come into play.
Design patterns are solutions to common problems software developers face during software development.
Let's examine the Design Patterns in items for a better understanding:
- It is generally based on OOP. But it can be used regardless of language and technology.
- They are proven solution methods used by software developers.
- They are the general solution plans applied to the problem.
We collect Design Patterns under 3 headings:
- Creative Patterns
- Structural Patterns
- Behavioral Patterns
In this article, I will talk about Creative Patterns:
Creational Patterns
It is a pattern used in the creation and management of objects. They provide object creation mechanisms that increase code flexibility and reusability.
Factory Method
It defines an interface to create a single object and allows subclasses to decide which class to instantiate.
Example: Let's define a class named Person.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Now let's add our Factory method:
class PersonFactory {
static add(name, age) {
return new Person(name, age);
}
}
Now we can create a new Person object using our PersonFactory model:
const person = PersonFactory.add("furkan", 24);
console.log(person)
> Output:
> Person { name: 'furkan', age: 24 }
Abstract Factory
Abstract Factory is a design pattern that we can use when we want to process multiple objects at the same time.
Example: Let's continue with the Person example and create another class named Client derived from the Person class:
class Person {
consume() {}
}
class Client extends Person {
consume() {
console.log("Client")
}
}
Now let's create factory methods for them and see how abstract is used:
class PersonFactory {
prepare(name)
}
class ClientFactory extends PersonFactory {
addClient() {
console.log("Client created")
return new Client();
}
}
Now it's time to use our abstract factory method:
const clientUserFact = new ClientFactory();
const person = clientUserFact.addClient();
person.consume();
> Output:
> Client created
> Client
Builder
This design allows you to create different types and representations of an object using the same construction code.
Example: Let's continue with our classic Person example. Here we will slightly modify the Person object:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return (
`${this.name} is ${this.age} years old!`
)
}
}
We use two pieces of information in the Person object: name and age. Now let's define a Person Builder:
class PersonBuilder {
constructor(person = new Person()) {
this.person = person;
}
get age() {
return new PersonAgeBuilder(this.person);
}
get name(){
return new PersonNameBuilder(this.person);
}
build() {
return this.person;
}
}
We said above that our object contains two pieces of information. Now let's create the builders of those objects here:
class PersonNameBuilder extends PersonBuilder {
constructor(person) {
super(person)
}
is(name) {
this.person.name = name;
return this;
}
}
class PersonAgeBuilder extends PersonBuilder {
constructor(person) {
super(person)
}
is(age) {
this.person.age = age;
return this;
}
}
Now it's time to use the objects we wrote:
const personBuilder = new PersonBuilder();
const person = personBuilder
.name.is("Furkan")
.age.is(24)
.build();
console.log(person.toString());
> Output:
> Furkan is 24 years old!
Prototype
Prototype is a design pattern that allows you to copy existing objects without making your code dependent on their classes.
Example: We came to our Person object again :D Here our Person object will be as follows:
class Person {
constructor(name) {
this.name = name;
}
setName(name) {
this.name = name;
console.log(name.toString())
}
clone() {
return new Person(this.name)
}
}
We said the purpose is to copy and we put a method called clone inside our object. Now let's use this and clone our object:
const person1 = new Person();
person1.setName("furkan");
const person2 = person1.clone();
person2.setName("tugay");
> Output:
> furkan
> tugay
Singleton
A singleton is used to ensure that there is only one instance of an object and to be called the same everywhere in your code when you need that object.
This is also similar to the “Single Responsibility Principle” in the SOLID principle.
Example: We have come to our last example where we will use the Person object.
class Person {
constructor() {
const instance = this.constructor.instance;
if(instance) {
return instance;
}
this.constructor.instance = this;
}
toString() {
console.log("Person Class");
}
}
We can also check if singleton is provided in this way:
const person1 = new Person();
const person2 = new Person();
console.log("is same: ", (person1 === person2));
person1.toString();
> Output:
> Person Class
In this article, I talked about what Design Patterns are and tried to explain Creative Patterns with JavaScript codes.
I will share two more articles depending on this article. These:
- Design Patterns in JavaScript: Structural Patterns
- Design Patterns in JavaScript: Behavioral Patterns
I hope it was a useful article for you. Don't forget to like and follow me on twitter to support me :D
Top comments (4)
Good article, I enjoyed reading it! If you're interested, feel free to check out my articles as well
helpful
It's a great article Furkan, thanks for sharing
Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍
Some comments have been hidden by the post's author - find out more