Pattern - Prototype
Tags: javascript, cleancode, webdev, programming
Published: 2023-01-14 15:13:30


![Pattern Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dizveowajcjn5fdk1rlo.png)

The _Prototype_ pattern was created by Gamma et al. in his book "Design Patterns: Elements of Reusable Object-Oriented Software", published in 1995. This _Prototype_ pattern is a creational design pattern in software development.

It is used to create new objects by copying existing objects, instead of creating new objects from scratch. The purpose of this pattern is to reduce the complexity of object creation and allow new objects to be created without specifying their classes. It is a good practice for dealing with complex object creation issues, and can be used to facilitate the implementation of shallow and deep object copying mechanisms.

The pattern is implemented by creating a "_Prototype_" interface that defines a "clone" method for creating copies of an object. Concrete classes implement this method to create copies of themselves. This pattern is useful when creating new objects might be costly or impractical, such as when objects need to be created at runtime or when objects are instantiated dynamically.

The _Prototype_ pattern has several advantages, including:

- **Creating objects without specifying their classes**: The pattern allows new objects to be created without specifying their classes, which means that classes only need to be defined once and then can be used to create new objects. This helps keep the code clean and maintainable.
- **Reduced complexity of object creation**: The pattern helps to reduce the complexity of object creation, allowing objects to be created quickly and easily.
- **Possibility of creating objects at runtime**: The pattern allows objects to be created at runtime, which means that new objects can be created dynamically.
- **Support for shallow and deep copies**: The pattern supports creating shallow and deep copies of objects. Shallow copy creates a copy of the object but shares the same underlying data. Deep copy creates a complete copy of the object and underlying data.
- **Code reuse**: The pattern allows already written and tested code to be reused to create new objects, which helps to save time and effort.
- **Easy to change implementation**: as the objects are created from existing prototypes, it's easy to change the implementation without having to refactor much of the code
- **Flexibility**: the use of the prototype pattern allows us to change the behavior or state of a class without having to modify the source code
- **Loose coupling**: The pattern has a loose coupling between classes, which means that classes are independent of each other and can be easily modified or replaced without affecting other classes.

Below is a simple code example using the Prototype pattern.


```js

// Interface Prototype
class Prototype {
    clone() {}
}

// Concrete Prototype
class ConcretePrototypeA extends Prototype {
    constructor(name) {
        super();
        this.name = name;
    }
    clone() {
        return new ConcretePrototypeA(this.name);
    }
}

// Usage
let prototypeA = new ConcretePrototypeA("Prototype A");
let copyOfPrototypeA = prototypeA.clone();
console.log(copyOfPrototypeA.name); // Output: "Prototype A"

```

In this example, the _Prototype_ class is an interface that defines the clone method. The _ConcretePrototypeA_ class is a concrete implementation of the Prototype class and implements the clone method to create a copy of the object.
On usage, a _ConcretePrototypeA_ object is created and stored in the _prototypeA_ variable, and soon after it is cloned to another object and stored in the _copyOfPrototypeA_ variable.

As mentioned earlier, this way of implementing it can be a way of making deep copies, but it is important to remember that this pattern has several ways of being implemented, and some libraries already have implementations of object clones, for example _lodash.cloneDeep()_ .

_Simple, right?_

Imagine another scenario in which you need to perform a search and insert data via a form through an entry point that is an API.

Api listed was:

- [ReqRes](https://reqres.in/)

Follow the solution below:


```js
// Interface Prototype
class Request {
    constructor(url) {
        this.url = url;
    }
    clone() {}
    makeRequest() {}
}

// Concrete Prototype
class GetRequest extends Request {
    constructor(url) {
        super(url);
    }
    clone() {
        return new GetRequest(this.url);
    }
    makeRequest() {
        return fetch(this.url).then((response) => response.json())
    }
}

class PostRequest extends Request {
    constructor(url, body) {
        super(url);
        this.body = body;
    }
    clone() {
        return new PostRequest(this.url, this.body);
    }
    makeRequest() {
        return fetch(this.url, { 
            method: 'POST', 
            headers: { 'Content-Type': 'application/json'}, 
            body: JSON.stringify(this.body)
        }).then((response) => response.json())
    }
}

// Usage
let getRequest = new GetRequest("https://reqres.in/api/users");
let postRequest = new PostRequest("https://reqres.in/api/users", { "name": "morpheus", "job": "leader" });

let requests = [getRequest, postRequest, getRequest.clone(), postRequest.clone()];

requests.forEach(request => {
    request.makeRequest();
});

```

The _Request_ class is a prototype interface, which defines the constructor and the _clone()_ and _makeRequest()_ methods. The _GetRequest_ and _PostRequest_ classes are concrete prototypes, which extend the Request class and implement their own _clone()_ and _makeRequest()_ methods.

In the _GetRequest_ class, the _clone()_ method returns a new instance of _GetRequest_, with the same url as the current instance. The _makeRequest()_ method uses the _fetch()_ function to perform a _GET_ request to the specified url and returns the response in JSON format.

In the _PostRequest_ class, the _clone()_ method returns a new instance of _PostRequest_, with the same url and body as the current instance. The _makeRequest()_ method uses the _fetch()_ function to perform a POST request to the specified url, with the body specified in the constructor, and returns the response in JSON format.

At the end of the code, an instance of _GetRequest_ and another of _PostRequest_ is created. Next, a requests array is created and the original instances and their copies are added. Finally, the _makeRequest()_ method is called for all instances in the requests array.

The _Prototype_ pattern is useful when you need to create new objects from existing objects, without having to specify their class or type. Some situations where the _Prototype_ pattern can be applied include:

- When creating new objects is costly or time-consuming, and it is more efficient to create a copy of an existing object.
- When objects need to be modified dynamically, but still need to maintain their basic structure.
- When you need to create multiple instances of an object with minor variations, such as changing just a few attributes.
- When you need to avoid using multiple constructors or static methods to create different types of objects.

In general, the _Prototype_ pattern is a good choice when you need to create objects flexibly and efficiently without having to worry about the details of their implementation.

**Conclusion**

The _Prototype_ design pattern is a creation pattern that allows you to create new objects from existing objects without having to specify their class or type. This is done by implementing a cloning method that creates a copy of the original object. It is useful when creating new objects is costly or time-consuming, when objects need to be dynamically modified but still need to maintain their basic structure, when you need to create multiple instances of an object with small variations, or when you need to avoid using multiple constructors or static methods to create different types of objects.

Hope this helps, until next time.